ISO C (C99): File HexViewer

...του ubuntu και έργων ΕΛ/ΛΑΚ (Έργα-Οδηγοί-Προτάσεις)

Συντονιστής: konnn

ISO C (C99): File HexViewer

Δημοσίευσηαπό migf1 » 22 Φεβ 2012, 14:06

EDIT: ConsoleHexViewer 0.28e75A - Public

Download: http://www.box.com/s/9744f89956b4944457c1

Έχω σταματήσει να ασχολούμαι με το συγκεκριμένο project εδώ και περίπου 10 ημέρες (επειδή κουράστηκα, ίσως το ξαναπιάσω κάποια στιγμή). Το αναβάθμισα και συγκέντρωσα τα πάντα σε ένα μόνο rar αρχείο (το παραπάνω link).

Το πακέτο περιέχει αρχεία και οδηγίες για όλες τις πλατφόρμες τόσο για το compilation του κώδικα όσο και για τα εκτελέσιμα και για ANSI/Windows-1253 περιβάλλοντα και για UTF-8. Περιέχει επίσης οδηγίες για τη δημιουργία μεταφράσεων και σε άλλες γλώσσες (πέραν της Αγγλικής και της Ελληνικής που υπάρχουν ήδη).

Σε περιβάλλοντα Posix, υποστηρίζονται μέσω makefiles o gcc (Unix/Linux/MacOS) και το cygwin gcc tool-chain (Windows XP/Vista/7). Περιέχονται προς άμεση χρήση και τα εκτελέσιμα που βγάζουν σε Ubuntu 11.04, FreeBSD 8.2 και CygWin.

Σε Windows, υποστηρίζονται μέσω makefiles ή/και project-files η Pelles C και οποιοδήποτε port του gcc tool-chain λειτουργεί σε native Windows περιβάλλον (όπως για παράδειγμα το MinGW). Περιλαμβάνονται προς άμεση χρήση και τα εκτελέσιμα που βγάζουν.

Ότι bug βρείτε, πέραν αυτών που αναφέρονται στο readme, γράψτε το στο νήμα (θα προσπαθήσω να το διορθώσω, ειδικά αν είναι κάτι εύκολο) Επίσης, αν κάνετε τίποτα βελτιώσεις, διορθώσεις, μεταφράσεις, υποστήριξη άλλων compilers, δημιουργία εκτελέσιμων σε άλλες πλατφόρμες, κλπ, βάλτε τα κι αυτά στο νήμα (ή στείλτε τα μου) ,να τα βάλω προσθέσω στο συγκεντρωτικό Download ;)

FEATURES

Spoiler: show
Μορφοποιημένος Κώδικας: Επιλογή όλων
FEATURES
-------------------------------------------------------------------------------------
(items marked with * need more work, see "Limitations, Inconveniences, Bugs")

* unlimited filesizes (by default uses a 2Gb limit, for faster loading times)
- multilingual (currently in English & Greek)
- syntax highlighting (printable, non-printable & zeroed bytes)
- color themes (currently: black, blue, red, gray)
- 8-bit ASCII support (adopts to any ASCII compatible encoding, including ANSI and UTF-8)
- byte groups (view contents grouped by 4, 8 or 16 bytes)
* sizes (base2/8/10/16 display in both endians, for any 8/16/32/64bit area)
- bookmarks (up to 16 bookmarks, used either by label or by id)
- moving (absolute & relative moving to any byte/row/page)
- jumping (direct jump to start & end of current file/page/row)
- normal search (bi-directional search for either hex or ascii strings)
- negated search (bi-directional skipping of consecutive same bytes/byte sequences)
- endianess conversion (conversion & saving of selected contents, as binary or as hexdumps)
- shell access (access to system's shell/command-line)
- repeat last command (by hitting the ENTER key... a simple but rather useful gimmick)
- pageable help

* Πρόβλημα στα μεγάλα αρχεία παρουσιάζεται μονάχα σε Windows με Pelles-C , ενώ πρόβλημα στα sizes
παρουσιάζεται μονάχα σε Windows με το Cygwin GCC tool-chain. Με το MinGW32 GCC toool-chain το
μόνο πρόβλημα που παρουσιάζεται είναι πως οι long-double στα sizes εμφανίζονται μηδενικοί.

Στο GCC tool-chains των Ubuntu/FreeBSD δεν έχω εντοπίσει κανένα πρόβλημα.


SCREEN-SHOTS

Νεότερα screen-shots μπορείτε να δείτε εδώ: http://www.insomnia.gr/topic/442635-cro ... p__4675424

ΥΓ1. Ο κώδικας σε πολλά σημεία είναι σε κατάσταση "1st draft".
ΥΓ2. Αφήνω παρακάτω μέσα σε παραθέσεις τα μηνύματα από τις προηγούμενες εκδόσεις.

έγραψε:
EDIT: Fix 0.261A - Public (αποκλειστικά για Alpha testing)

Ανοίξτε τα spoilers για τον διορθωμένο κώδικα των αρχείων: con_color.h και hexview.c (το αρχείο hexview.h δεν αλλάχτηκε, οπότε δεν το συμπεριλαμβάνω). Διορθώνει πρόβλημα με τα χρώματα σε ANSI τερματικά (λεπτομέρειες εδώ: https://forum.ubuntu-gr.org/viewtopic.p ... 82#p233082).

Αρχείο: con_color.h (0.261A)
Spoiler: show
Μορφοποιημένος Κώδικας: Επιλογή όλων
#ifndef CON_COLOR_H
#define CON_COLOR_H

#include <string.h>

#if defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__) || defined(__TOS_WIN__)

#define CON_COLOR_WIN32

#elif defined(__linux__) || defined(__unix__) || defined(__unix) \
|| defined(__CYGWIN__) || defined(__GNU__) || defined(__MINGW32__) \
|| defined(__MINGW64__)

#define CON_COLOR_ANSI
#endif


#if 0 /* change to 1 to FORCE ANSI mode (for Windows you need: ansicon.exe)*/
#ifdef CON_COLOR_WIN32
#undef CON_COLOR_WIN32
#endif

#ifndef CON_COLOR_ANSI
#define CON_COLOR_ANSI
#endif
#endif

/* Windows ==================================================================== */
#if defined( CON_COLOR_WIN32 )

#include <windows.h>

HANDLE hStdout;
CONSOLE_SCREEN_BUFFER_INFO csbiInfo, csbiSaved, csbiTemp;

/* Win32 Macros */

#define CONOUT_INIT() \
do { \
hStdout = GetStdHandle( STD_OUTPUT_HANDLE ); \
if ( hStdout != INVALID_HANDLE_VALUE ) \
{ \
GetConsoleScreenBufferInfo(hStdout, &csbiInfo); \
memcpy( &csbiSaved, &csbiInfo, \
sizeof(CONSOLE_SCREEN_BUFFER_INFO) ); \
} \
else \
printf("*** CONOUT_INIT failed: %d!\n", GetLastError());\
} while(0)

#define CONOUT_SET_COLOR( color ) \
do { \
memcpy( &csbiTemp, &csbiInfo, \
sizeof(CONSOLE_SCREEN_BUFFER_INFO) ); \
csbiInfo.wAttributes = (color); \
SetConsoleTextAttribute( hStdout, (color) ); \
} while(0)

#define CONOUT_ADD_COLOR( color ) \
do { \
csbiInfo.wAttributes |= (color); \
SetConsoleTextAttribute(hStdout, csbiInfo.wAttributes); \
} while(0)

#define CONOUT_RESET() \
do { \
SetConsoleTextAttribute(hStdout, csbiTemp.wAttributes); \
memcpy( &csbiInfo, &csbiTemp, \
sizeof(CONSOLE_SCREEN_BUFFER_INFO) ); \
} while(0)

#define CONOUT_RESTORE() \
SetConsoleTextAttribute( hStdout, csbiSaved.wAttributes )

#define CONOUT_PRINTF(fg, bg, ...) \
do { \
if ( (fg) != FG_NOCHANGE ) \
CONOUT_SET_COLOR( (fg) ); \
if ( (bg) != BG_NOCHANGE ) \
CONOUT_ADD_COLOR( (bg) ); \
printf( __VA_ARGS__ ); \
if ( (fg) != FG_NOCHANGE || (bg) != BG_NOCHANGE ) \
CONOUT_RESET(); \
} while(0)


/* Win32 Foreground Colors */

#define FG_NOCHANGE -1
#define BG_NOCHANGE -1

#define FG_WHITE \
FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_INTENSITY

#define FG_GRAY FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE

#define FG_DARKGRAY FOREGROUND_INTENSITY
#define FG_BLACK 0x00

#define FG_RED FOREGROUND_RED|FOREGROUND_INTENSITY
#define FG_DARKRED FOREGROUND_RED

#define FG_GREEN FOREGROUND_GREEN|FOREGROUND_INTENSITY
#define FG_DARKGREEN FOREGROUND_GREEN

#define FG_BLUE FOREGROUND_BLUE|FOREGROUND_INTENSITY
#define FG_DARKBLUE FOREGROUND_BLUE

#define FG_YELLOW FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_INTENSITY
#define FG_DARKYELLOW FOREGROUND_RED|FOREGROUND_GREEN

#define FG_MAGENTA FOREGROUND_RED|FOREGROUND_BLUE|FOREGROUND_INTENSITY
#define FG_DARKMAGENTA FOREGROUND_RED|FOREGROUND_BLUE

#define FG_CYAN FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_INTENSITY
#define FG_DARKCYAN FOREGROUND_GREEN|FOREGROUND_BLUE

/* Win32 Background Colors */

#define BG_WHITE \
BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE|BACKGROUND_INTENSITY

#define BG_GRAY BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE

#define BG_DARKGRAY BACKGROUND_INTENSITY
#define BG_BLACK 0x00

#define BG_RED BACKGROUND_RED|BACKGROUND_INTENSITY
#define BG_DARKRED BACKGROUND_RED

#define BG_GREEN BACKGROUND_GREEN|BACKGROUND_INTENSITY
#define BG_DARKGREEN BACKGROUND_GREEN

#define BG_BLUE BACKGROUND_BLUE|BACKGROUND_INTENSITY
#define BG_DARKBLUE BACKGROUND_BLUE

#define BG_YELLOW BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_INTENSITY
#define BG_DARKYELLOW BACKGROUND_RED|BACKGROUND_GREEN

#define BG_MAGENTA BACKGROUND_RED|BACKGROUND_BLUE|BACKGROUND_INTENSITY
#define BG_DARKMAGENTA BACKGROUND_RED|BACKGROUND_BLUE

#define BG_CYAN BACKGROUND_GREEN|BACKGROUND_BLUE|BACKGROUND_INTENSITY
#define BG_DARKCYAN BACKGROUND_GREEN|BACKGROUND_BLUE

/* ANSI ====================================================================== */
#elif defined( CON_COLOR_ANSI )

/* ANSI Macros */

#define CONOUT_INIT()
#define CONOUT_SET_COLOR( color ) printf( color )
#define CONOUT_ADD_COLOR( color ) printf( color )
#define CONOUT_RESET() printf( "\033[0m" )
#define CONOUT_RESTORE() printf( "\033[0m" )

#define CONOUT_PRINTF(fg, bg, ...) \
do { \
if ( strcmp((fg), FG_NOCHANGE) ) \
CONOUT_SET_COLOR( (fg) ); \
if ( strcmp((bg), BG_NOCHANGE) ) \
CONOUT_ADD_COLOR( (bg) ); \
printf( __VA_ARGS__ ); \
if ( strcmp((fg), FG_NOCHANGE) || strcmp((bg), BG_NOCHANGE) )\
CONOUT_RESET(); \
} while(0)

/* ANSI Foreground Colors */

#define FG_NOCHANGE "\0"
#define BG_NOCHANGE "\0"

#define FG_WHITE "\033[1;37m"
#define FG_GRAY "\033[0;37m"

#define FG_DARKGRAY "\033[1;30m"
#define FG_BLACK "\033[0;30m"

#define FG_RED "\033[1;31m"
#define FG_DARKRED "\033[0;31m"

#define FG_GREEN "\033[1;32m"
#define FG_DARKGREEN "\033[0;32m"

#define FG_BLUE "\033[1;34m"
#define FG_DARKBLUE "\033[0;34m"

#define FG_YELLOW "\033[1;33m"
#define FG_DARKYELLOW "\033[0;33m"

#define FG_MAGENTA "\033[1;35m"
#define FG_DARKMAGENTA "\033[0;35m"

#define FG_CYAN "\033[1;36m"
#define FG_DARKCYAN "\033[0;36m"

/* ANSI Background Colors */

#define BG_WHITE "\033[47m"
#define BG_GRAY "\033[47m"

#define BG_DARKGRAY "\033[40m"
#define BG_BLACK "\033[40m"

#define BG_RED "\033[41m"
#define BG_DARKRED "\033[41m"

#define BG_GREEN "\033[42m"
#define BG_DARKGREEN "\033[42m"

#define BG_BLUE "\033[44m"
#define BG_DARKBLUE "\033[44m"

#define BG_YELLOW "\033[43m"
#define BG_DARKYELLOW "\033[43m"

#define BG_MAGENTA "\033[45m"
#define BG_DARKMAGENTA "\033[45m"

#define BG_CYAN "\033[46m"
#define BG_DARKCYAN "\033[46m"
#endif

#endif /* ifndef CON_COLOR_H */

Αρχείο: hexview.c (0.261A)
Spoiler: show
Μορφοποιημένος Κώδικας: Επιλογή όλων
/*****************************************************//**
* @brief Prmitive hexadecimal file viewer (pipe it to 'less' or 'more'
* to make it much less primitive... see Usage below).
* @file hexview.c
* @version 0.261A
* @date 29 Feb, 2012
* @author migf1 <mig_f1@hotmail.com>
* @par Language:
* C (ANSI C99)
* @par Usage:
* hexview [-raw] [filename]
* \n
* Use -raw as the 1st command-line argument to force raw output
* (useful for piping, e.g: hexview -raw file | less)
*
* @remark Feel free to experiment with the values of the pre-processor
* constants: FMT_NCOLS, FMT_PGLINES and FMT_POS. They affect the
* appearance of the output.
*********************************************************
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>

#include "con_color.h"
#include "hexview.h"

typedef unsigned char Byte;

typedef struct Buffer {
char fname[ MAXINPUT ]; /* name of the file to be viewed */
size_t len, nrows, npages; /* total Bytes, rows and pages */
// size_t bt, row, pg; /* current byte, row & page indicies */
Byte *data; /* the actual data buffer */
} Buffer;

typedef struct Settings {
_Bool colorize;
unsigned short int charset;
_Bool israw;
_Bool unlimfsize;
} Settings;

enum KeyCommand {
KEY_HLP = 'h',
KEY_QUIT = 'q',
KEY_COLOR = 'c',
KEY_CHARSET = 't',
KEY_LOADFILE = 'f',
KEY_TOP = '{',
KEY_BOT = '}',
KEY_PGUP = '[',
KEY_PGDN = ']',
KEY_ROWUP = ',',
KEY_ROWDN = '.',
KEY_ROWSTA = '(',
KEY_ROWEND = ')',
KEY_BYTEB = '<',
KEY_BYTEF = '>',
KEY_GPAGE = 'p',
KEY_GROW = 'r',
KEY_GBYTE = 'b',
KEY_FNDSTR = '/',
KEY_RFNDSTR = '\\',
KEY_FNDSEQ = ';',
KEY_RFNDSEQ = ':',
};

void buffer_cleanup( Buffer *buffer );
_Bool buffer_read_file_longmax( Buffer *buffer, const char *fname );
_Bool buffer_read_file( Buffer *buf, const char *fname, size_t chunklen );


/*********************************************************//**
* Return the size of a byte in bits
*************************************************************
*/
size_t bin_bitcount( Byte byte )
{
return 8U * sizeof(byte);
}

/*********************************************************//**
* Return a bitstring from a given (decimal) byte.
*************************************************************
*/
char *bin_byte2bitstring( Byte byte )
{
int len = bin_bitcount( byte );
char *bitstring = calloc( len + 1, sizeof(char) );
if ( !bitstring )
return NULL;

memset(bitstring, '0', len--);
while ( byte && len > -1) {
bitstring[len--] = (byte & 1) ? '1' : '0';
byte >>= 1;
}

return bitstring;
}

/*********************************************************//**
* Read a c-string from stdin.
*************************************************************
*/
char *s_read( char *s, size_t maxlen )
{
size_t len = 0U;

if ( !s || !fgets( s, maxlen, stdin) )
return NULL;

if ( maxlen > MAXINPUT)
maxlen = MAXINPUT;

if ( s[ (len=strlen(s))-1 ] == '\n')
s[ len-1 ] = '\0';

return s;
}

/*********************************************************//**
*
*************************************************************
*/
_Bool fileexists(const char *fname)
{
FILE *fp = fopen(fname, "rb");
if ( !fp )
return false;

fclose(fp);
return true;
}

/*********************************************************//**
* Return the size of a file in bytes, or -1 on error (cannot be more than LONG_MAX).
*************************************************************
*/
long int filesize(const char *fname)
{
long int size;
FILE *fp;

if ( NULL == (fp = fopen(fname, "rb")) ) /* binary mode */
return -1;

if( fseek(fp, 0, SEEK_END) ) {
fclose(fp);
return -1;
}

size = ftell(fp);
fclose(fp);

return size;
}

/*********************************************************//**
* Display help screen.
*************************************************************
*/
void show_help( const _Bool colorize )
{
CLS();

colorPRINTF( colorize, FGCLR_EM1, BG_NOCHANGE, "%52s\n\n", NAME_VERSION );

#if DISABLED // ==============================================
/* list of command line arguments */

colorPRINTF( colorize, FGCLR_EM1, BG_NOCHANGE, "Command Line Arguments\n\n" );

puts( "-raw \t\t Force raw output (useful for piping)" );

puts( "\0" );
#endif // ==============================================

/* list of available commands */

colorPRINTF( colorize, FGCLR_EM1, BG_NOCHANGE, "Available Commands\n" );

puts( "Commands are NOT case-sensitive but require you to press ENTER at the end.\n" );
printf( "%c \t\t This help screen\n", KEY_HLP );
printf( "%c \t\t Quit the program\n", KEY_QUIT );
puts( "ENTER \t\t Repeat last command" );
printf( "%cfilename\t Load a new file (leave NO blanks between %c and filename)\n",
KEY_LOADFILE, KEY_LOADFILE
);
printf( "%c \t\t Toggle colorization (on/off)\n", KEY_COLOR );
printf( "%c\t\t Toggle ASCII character set (plain/extended)\n", KEY_CHARSET);

putchar('\n');

printf( "%c or %c \t\t Start or end of file\n", KEY_TOP, KEY_BOT );
printf( "%c or %c \t\t Start or end of row (line)\n", KEY_ROWSTA, KEY_ROWEND);
printf( "%c or %c n\t Move n bytes back or forward (1 is assumed if no n is present)\n",
KEY_BYTEB, KEY_BYTEF
);
printf( "%c or %c n\t Move n rows up or down (1 is assumed if no n is present)\n",
KEY_ROWUP, KEY_ROWDN
);
printf( "%c or %c n\t Move n pages up or down (1 is assumed if no n is present)\n",
KEY_PGUP, KEY_PGDN );
printf( "%c n \t\t Goto n'th byte (0xn for hex, 0n for oct)\n", KEY_GBYTE);
printf( "%c n \t\t Goto n'th row (0xn for hex, 0n for oct)\n", KEY_GROW );
printf( "%c n \t\t Goto n'th page\n", KEY_GPAGE);

putchar('\n');

printf( "%c or %c string\t Search ahead or backwards for a text-string (case sensitive)\n",
KEY_FNDSTR, KEY_RFNDSTR
);
printf( "%c or %c sequence\t Search ahead or backwards for a byte-sequence\n",
KEY_FNDSEQ, KEY_RFNDSEQ
);

putchar('\n');
pressENTER();

return;
}

/*********************************************************//**
* Display text labels and other info on the currently displayed page.
*************************************************************
*/
void show_header( const size_t btcurr, const Buffer *buffer, const Settings *settings )
{
unsigned short int i;

if ( !buffer || !buffer->data )
return;

CLS();

/* text label for file-offset */
colorPRINTF(
settings->colorize, FGCLR_ROWOFST, BG_NOCHANGE,
" %-*s ", FMT_OFST,"OFFSET"
);

/* hex indicies for Bytes */
for (i=0; i < FMT_NCOLS; i++)
{
char *fmt = (btcurr % FMT_NCOLS == i) ? "%-1hX* " : "%-2hX ";

if ( i != 0 && i % FMT_GRPCOLS == 0 ) /* group columns */
putchar(' ');

if ( btcurr % FMT_NCOLS == i )
colorPRINTF(settings->colorize,FGCLR_BYTCURR,BG_NOCHANGE, fmt,i);
else
colorPRINTF(settings->colorize,FGCLR_ROWOFST,BG_NOCHANGE, fmt,i);
}

/* hex indicies for Characters */
putchar(' ');
for (i=0; i < FMT_NCOLS; i++)
{
if ( btcurr % FMT_NCOLS == i )
colorPRINTF(
settings->colorize, FGCLR_BYTCURR, BG_NOCHANGE, "%hX", i
);
else
colorPRINTF(
settings->colorize, FGCLR_ROWOFST,BG_NOCHANGE,
"%hX", i
);
}
putchar('\n');

/* separating lines */

putchar(' ');
for (i=0; i < FMT_OFST + 1; i++)
colorPRINTF( settings->colorize, FGCLR_ROWOFST, BG_NOCHANGE, "-" );

for (i=0; i < FMT_NCOLS; i++)
{
if (i != 0 && i % FMT_GRPCOLS == 0 ) /* group separation */
colorPRINTF(settings->colorize, FGCLR_ROWOFST,BG_NOCHANGE, "-");

colorPRINTF(
settings->colorize, FGCLR_ROWOFST, BG_NOCHANGE,
(btcurr % FMT_NCOLS == i) ? "..-" : "---"
);
}
putchar('\b');
printf(" ");
for (i=0; i < FMT_NCOLS; i++)
{
colorPRINTF(
settings->colorize, FGCLR_ROWOFST, BG_NOCHANGE,
(btcurr % FMT_NCOLS == i) ? "." : "-"
);
}

putchar('\n');

return;
}

/*********************************************************//**
* Display the prompt (it conists of 2 lines).
*************************************************************
*/
_Bool show_prompt(
const size_t bt,
char *cmd,
const char *prevcmd,
const Buffer *buffer,
const Settings *settings
)
{
size_t row = 0U, slen = 0U;
char *cp = NULL, *bitstr = NULL;

if ( !cmd || !prevcmd || !buffer || !settings || !buffer->data)
return false;

/* -----------------------
* display 1st prompt line
*/

/* filename (display FNAME_SHOWLEN last chars, if longer) */
slen = strlen( buffer->fname );
if ( slen > FNAME_SHOWLEN )
cp = (char *) &buffer->fname[ slen-FNAME_SHOWLEN ];
else
cp = (char *) &buffer->fname;
colorPRINTF(
settings->colorize,
FGCLR_PMTFNAME,
BGCLR_PMTFNAME,
" %s%s ",
cp != buffer->fname ? "..." : "\0",
cp
);

putchar(':');

/* filesize (in Mbytes) */
colorPRINTF(
settings->colorize, FGCLR_PMTFNAME, BGCLR_PMTFNAME,
" %.3f Mb :", ( (buffer->len * sizeof(Byte)) / (1024.0 * 1024) )
);

/* filesize in viewer-rows */
colorPRINTF(
settings->colorize, FGCLR_PMTFNAME, BGCLR_PMTFNAME,
" %llu rows ", (unsigned long long) (buffer->nrows)
);

row = BT2ROW(bt, buffer->len, buffer->nrows); /* calc the row index for bt */

putchar('|');

/* filesize in viewer-pages */
colorPRINTF(
settings->colorize, FGCLR_PMTPG, BGCLR_PMTPG,
" Pg:%llu/%llu ",
(unsigned long long) (1 + ROW2PG(row, buffer->nrows)),
(unsigned long long) (buffer->npages)
);

putchar('|');

/* selected character set */
colorPRINTF(
settings->colorize, FGCLR_PMTCHRSET, BGCLR_PMTCHRSET,
" %s ", NAME_CHARSET(settings->charset)
);
puts("\0");

/* -----------------------
* display 2nd prompt line
*/

/* current byte position */
colorPRINTF(
settings->colorize, FGCLR_PMTBYTPOS, BGCLR_PMTBYTPOS,
" %llu=%llx/%llX ",
(unsigned long long) bt,
(unsigned long long) bt,
(unsigned long long) buffer->len - 1
);
/* current row position */
colorPRINTF(
settings->colorize, FGCLR_PMTROWPOS, BGCLR_PMTROWPOS,
"[%llx] ",
(unsigned long long) row
);

putchar('|');
/* decimal values of current byte (unsigned & signed) */
colorPRINTF(
settings->colorize, FGCLR_PMTDEC, BGCLR_PMTDEC,
" d:%hhu %hhd ",
buffer->data[bt],
buffer->data[bt] > 127 ? buffer->data[bt] - 256 : buffer->data[bt]
);

putchar('|');
/* octal value of current byte */
colorPRINTF(
settings->colorize, FGCLR_PMTOCT, BGCLR_PMTOCT,
" o:%hho ",
buffer->data[bt]
);

putchar('|');
/* binary value of current byte */
colorPRINTF(
settings->colorize, FGCLR_PMTBIN, BGCLR_PMTBIN,
" %s ",
(bitstr = bin_byte2bitstring( buffer->data[bt] )) ? bitstr : "error"
);
if ( bitstr )
free(bitstr);

putchar('|');

/* previous command */
colorPRINTF(settings->colorize, FGCLR_PMTPRVCMD, BGCLR_PMTPRVCMD, " %s ", prevcmd );

/* user prompt */
colorPRINTF(settings->colorize, FGCLR_EM1, BG_NOCHANGE, ": ");

fflush( stdout );

/* read the user command */
if ( !fgets( cmd, MAXINPUT, stdin ) )
return false;

/* if not just an ENTER, remove '\n' from the end */
slen = strlen(cmd);
if ( '\n' != *cmd && '\n' == cmd[ slen-1 ] )
cmd[ slen-1 ] = '\0';

return true;
}

/*********************************************************//**
* List the contents of a row in hex/char format.
*************************************************************
*/
_Bool view_row(
const size_t row,
const size_t btcurr,
const Buffer *buffer,
const Settings *settings
)
{
char clead; /* leading displayed char */
size_t i;
const size_t row2idx = row * FMT_NCOLS;

if ( !buffer || !buffer->data || row2idx > buffer->len )
return false;

/* display row offset */
clead = row == btcurr / FMT_NCOLS ? '*' : ' ';
if ( row == btcurr / FMT_NCOLS )
colorPRINTF(
settings->colorize, FGCLR_BYTCURR, BG_NOCHANGE,
"%c%0*lX ", clead, FMT_OFST,(long unsigned)row2idx
);
else
colorPRINTF(
settings->colorize, FGCLR_ROWOFST, BG_NOCHANGE,
"%c%0*lX ", clead, FMT_OFST,(long unsigned)row2idx
);

/* display row's contents as bytes */
for (i=0; i < FMT_NCOLS && row2idx + i < buffer->len; i++)
{
Byte byte = buffer->data[row2idx + i];
const _Bool isPrintable = (settings->charset == FMT_ASCII)
? isprint((int)byte)
: byte > 31;

if ( i != 0 && i % FMT_GRPCOLS == 0 ) /* group columns */
putchar(' ');

if ( isPrintable ) /* printable byte */
{
if ( btcurr != row2idx + i )
colorPRINTF(
settings->colorize, FGCLR_BYTPRT1, BG_NOCHANGE,
"%02hX ", byte );
else
colorPRINTF(
settings->colorize, FGCLR_BYTCURR, BG_NOCHANGE,
"%02hX ", byte );
}
else if ( byte == 0 ) /* zeroed byte */
{
if ( btcurr != row2idx + i )
colorPRINTF(
settings->colorize, FGCLR_BYTZERO, BG_NOCHANGE,
"%02hX ", byte );
else
colorPRINTF(
settings->colorize, FGCLR_BYTCURR, BG_NOCHANGE,
"%02hX ", byte );
}
else /* non-printable byte */
{
if ( btcurr != row2idx + i )
colorPRINTF(
settings->colorize, FGCLR_BYTPRT0, BG_NOCHANGE,
"%02hX ", byte );
else
colorPRINTF(
settings->colorize, FGCLR_BYTCURR, BG_NOCHANGE,
"%02hX ", byte );
}
}
for (; i < FMT_NCOLS; i++)
printf(" ");
putchar(' ');

/* display row's contents as ASCII chars */
for (i=0; i < FMT_NCOLS && row2idx + i < buffer->len; i++)
{
int c = (int)buffer->data[row2idx + i];
const _Bool isPrintable = (settings->charset == FMT_ASCII)
? isprint(c)
: (c>31);

if ( isPrintable ) /* printable byte */
{
if ( btcurr != row2idx + i )
colorPRINTF(
settings->colorize, FGCLR_BYTPRT1, BG_NOCHANGE,
"%c", c );
else
colorPRINTF(
settings->colorize, FGCLR_BYTCURR, BG_NOCHANGE,
"%c", c );
}
else if ( c == '\0' ) /* zero-byte char */
{
if ( btcurr != row2idx + i )
colorPRINTF(
settings->colorize, FGCLR_BYTZERO, BG_NOCHANGE, "." );
else
colorPRINTF(
settings->colorize, FGCLR_BYTCURR, BG_NOCHANGE,
"." );
}
else /* non-printable char */
{
if ( btcurr != row2idx + i )
colorPRINTF(
settings->colorize, FGCLR_BYTPRT0, BG_NOCHANGE, "." );
else
colorPRINTF(
settings->colorize, FGCLR_BYTCURR, BG_NOCHANGE, "." );
}
}
for (; i < FMT_NCOLS; i++)
putchar(' ');
putchar('\n');


return true;
}

/*********************************************************//**
*
*************************************************************
*/
_Bool view_screen( const size_t btcurr, const Buffer *buffer, const Settings *settings )
{
size_t i, rowstart; /* for parsing rows */

if ( !buffer || !buffer->data )
return false;

rowstart = BT2ROW(btcurr, buffer->len, buffer->nrows);

for (i=0; i < FMT_PGLINES && (i+rowstart) < buffer->nrows; i++)
view_row( (i+rowstart), btcurr, buffer, settings );

/* if necessary, fill rest of the page with blank rows */
for (; i < FMT_PGLINES; i++)
putchar('\n');

return true;
}

/*********************************************************//**
*
*************************************************************
*/
_Bool do_command(
size_t *bt, /* by reference */
const char *cmd,
const char *prevcmd,
Buffer *buffer,
Settings *settings /* by reference */
)
{
enum KeyCommand key;
size_t row;

if ( !buffer || !buffer->data )
return false;

/* execute the command */

row = BT2ROW( *bt, buffer->len, buffer->nrows );
key = tolower( (int) *cmd );

/* display the help screen */
if ( KEY_HLP == key ) {
show_help( settings->colorize );
return true;
}

/* load a new file */
if ( KEY_LOADFILE == key )
{
_Bool success = false;
char answer[256+1] = {'n'};
char tmpfname[ MAXINPUT ] = {'\0'};

if ( '\0' == cmd[1] ) {
printf( "f must be followed by a filename! " );
pressENTER();
return true;
}

strncpy( tmpfname, &cmd[1], MAXINPUT );
if ( !fileexists(tmpfname) ) {
printf( "No such file, keeping current one! " );
pressENTER();
return true;
}

colorPRINTF(
settings->colorize, FG_RED, BG_NOCHANGE,
"Current file will be closed, are you sure (y/) ? "
);
if ( 'y' != tolower( (int) *s_read(answer, 256+1) ) )
return true;

buffer_cleanup( buffer );
success = (settings->unlimfsize)
? buffer_read_file( buffer, tmpfname, 100*1024*1024 )
: buffer_read_file_longmax( buffer, tmpfname );
if ( !success ) {
perror(NULL);
return true;
}

return true;
}

/* toggle colorization */
if ( KEY_COLOR == key ) {
settings->colorize = (settings->colorize == true ) ? false : true;
return true;
}

/* toggle character set */
if ( KEY_CHARSET == key ) {
settings->charset = (settings->charset == FMT_ASCII)
? FMT_XASCII : FMT_ASCII;
return true;
}

/* byte back/forward */
if ( KEY_BYTEB == key || KEY_BYTEF == key )
{
/* get relative step (if any) */
long long step = strtoll( &cmd[1], NULL, 10 );
if (errno == ERANGE) /* over/underflowed step */
return true;
if ( step == 0 ) /* no step ? assume 1 */
step = 1;
else if ( step < 0 ) /* negative step? negate it */
step = -step;

/* apply relative row-step */
if ( KEY_BYTEB == key )
*bt = (*bt > step - 1) ? *bt - step : 0;
else /* KEY_BYTEF == key */
*bt = (*bt < buffer->len - 1 - step)
? *bt + step
: buffer->len - 1;

return true;
}

/* row start/end */
if ( KEY_ROWSTA == key ) {
*bt = ROW2BT(row, buffer->nrows);
return true;
}
if ( KEY_ROWEND == key ) {
*bt = ROW2BT(row, buffer->nrows) + FMT_NCOLS - 1;
return true;
}

/* row up/down */
if ( KEY_ROWUP == key || KEY_ROWDN == key )
{
/* get relative row-step (if any) */
long long step = strtoll( &cmd[1], NULL, 10 );
if (errno == ERANGE) /* over/underflowed step */
return true;
if ( step == 0 ) /* no step ? assume 1 */
step = 1;
else if ( step < 0 ) /* negative step? negate it */
step = -step;

/* apply relative row-step */
if ( KEY_ROWUP == key )
row = (row > step - 1) ? row - step : 0;
else /* KEY_ROWDN == key */
row = (row < buffer->nrows - 1 - step)
? row + step
: buffer->nrows - 1;
}

/* page up/down */
else if ( KEY_PGUP == key || KEY_PGDN == key )
{
/* get relative page-step (if any) */
long long step = strtoll( &cmd[1], NULL, 10 );
if (errno == ERANGE) /* over/underflowed step */
return true;
if ( step == 0 ) /* no step ? assume 1 */
step = 1;
else if ( step < 0 ) /* negative step? negate it */
step = -step;

/* apply relative page-step */
if ( KEY_PGUP == key )
row = row > step * (FMT_PGLINES - 1)
? row - step * FMT_PGLINES
: 0;
else /* KEY_PGDN == key */
row = myMIN( (row + step * FMT_PGLINES), buffer->nrows - 1 );
}

/* top/bottom of file */
else if ( KEY_TOP == key ) {
*bt = 0;
return true;
}
else if ( KEY_BOT == key ) {
*bt = buffer->len - 1;
return true;
}

/* goto to specified byte */
else if ( KEY_GBYTE == key ) {
size_t newbt;
sscanf( &cmd[1], "%li", (long int *)&newbt );
row = BT2ROW(newbt, buffer->len, buffer->nrows);
*bt = newbt > buffer->len - 1 ? buffer->len - 1 : newbt;
return true;
}
/* goto to specified row */
else if ( KEY_GROW == key ) {
size_t newrow;
sscanf( &cmd[1], "%li", (long int *)&newrow );
row = newrow > buffer->nrows - 1
? buffer->nrows - 1
: newrow > 0 ? newrow : 0;
}
/* goto to specified page */
else if ( KEY_GPAGE == key ) {
size_t newpg = strtoul( &cmd[1], NULL, 10 );
--newpg;
row = PG2ROW(newpg, buffer->npages);
}

/* search forward for text-string */
else if ( KEY_FNDSTR == key )
{
size_t ibt = *bt; /* remember cursor position */
size_t slen = strlen( &cmd[1] );
int tmp = 1;

if ( !strcmp(cmd, prevcmd) ) /* fix ibt if cmd == prevcmd */
ibt = ibt > 0 ? ibt+1 : 1;

/* do the search */
colorPRINTF(settings->colorize, FG_RED, BG_NOCHANGE, "searching..." );
while ( slen && ibt < buffer->len - slen + 1
&& (tmp = memcmp(&buffer->data[ibt], (Byte *)&cmd[1], slen * sizeof(Byte)))
)
ibt++;

if ( 0 == tmp ) /* string found */
*bt = ibt; /* ... update cursor position */
else
BELL(1);

return true;
}
/* search backwards for text-string */
else if ( KEY_RFNDSTR == key )
{
size_t ibt = *bt; /* remember cursor position */
size_t slen = strlen( &cmd[1] );
int tmp = 1;

if ( !strcmp(cmd, prevcmd) ) /* fix ibt if cmd == prevcmd */
ibt = ibt > 0 ? ibt-1 : 0;

/* do the search */
colorPRINTF(settings->colorize, FG_RED, BG_NOCHANGE, "searching..." );
while ( slen && ibt > 0
&& (tmp=memcmp(&buffer->data[ibt], (Byte *)&cmd[1], slen * sizeof(Byte)))
)
ibt--;
/* 0 is treaded separately because ibt is unsigned */
if ( ibt == 0 && tmp != 0 )
tmp = memcmp(&buffer->data[ibt], (Byte *)&cmd[1], slen * sizeof(Byte));

if ( 0 == tmp ) /* string found */
*bt = ibt; /* ... update cursor position */
else
BELL(1);

return true;
}

/* search forward for byte-sequence */
else if ( KEY_FNDSEQ == key )
{
size_t ibt = *bt; /* remember cursor position */
size_t iseq; /* eventually the len of seq[]*/
Byte seq[MAXINPUT] = {0}; /* to hold the byte-sequence */
int tmp = 1; /* general purpose temp int */

if ( !strcmp(cmd, prevcmd) ) /* fix ibt if cmd == prevcmd */
ibt = ibt > 0 ? ibt+1 : 1;

/* convert text-string &cmd[1] to byte-sequence seq[] */
tmp = iseq = 0;
while ( 1 == sscanf(&cmd[tmp+1], "%2hhx", (Byte *)&seq[iseq]) )
{
tmp += 2;
iseq++;
}
seq[iseq] = '\0'; /* this is just for debugging */

/* do the search */
colorPRINTF(settings->colorize, FG_RED, BG_NOCHANGE, "searching..." );
while ( iseq && ibt < buffer->len - iseq + 1
&& (tmp=(memcmp( &buffer->data[ibt], seq, iseq*sizeof(Byte) )))
)
ibt++;

if ( 0 == tmp ) /* sequence found */
*bt = ibt; /* ... update cursor position */
else
BELL(1);

return true;
}
/* search backwards for byte-sequence */
else if ( KEY_RFNDSEQ == key )
{
size_t ibt = *bt; /* remember cursor position */
size_t iseq; /* eventually the len of seq[]*/
Byte seq[MAXINPUT] = {0}; /* to hold the byte-sequence */
int tmp = 1; /* general purpose temp int */

if ( !strcmp(cmd, prevcmd) ) /* fix ibt if cmd == prevcmd */
ibt = ibt > 0 ? ibt-1 : 0;

/* convert text-string &cmd[1] to byte-sequence seq[] */
tmp = iseq = 0;
while ( 1 == sscanf(&cmd[tmp+1], "%2hhx", (Byte *)&seq[iseq]) )
{
tmp += 2;
iseq++;
}
seq[iseq] = '\0'; /* this is just for debugging */

/* do the search */
colorPRINTF(settings->colorize, FG_RED, BG_NOCHANGE, "searching..." );
while ( iseq && ibt > 0
&& (tmp=memcmp(&buffer->data[ibt], seq, iseq * sizeof(Byte))) )
ibt--;
/* 0 is treaded separately because ibt is unsigned */
if ( ibt == 0 && tmp != 0 )
tmp = memcmp(&buffer->data[ibt], seq, iseq * sizeof(Byte));

if ( 0 == tmp ) /* string found */
*bt = ibt; /* ... update cursor position */
else
BELL(1);

return true;
}

/*
else
(*row) += FMT_PGLINES;
*/
*bt = ROW2BT( row, buffer->nrows ) + ( *bt % FMT_NCOLS );

return true;
}

/*********************************************************//**
*
*************************************************************
*/
_Bool view_buffer( Buffer *buffer, Settings *settings )
{
size_t bt; /* current byte-index */
char cmd[ MAXINPUT ] = {']'}, prevcmd[ MAXINPUT ] = {'\0'};

if ( !buffer || !buffer->data || !settings )
return false;

bt = 0;
for (;;)
{
if ( !settings->israw ) /* no headers in raw-mode */
show_header( bt, buffer, settings );

view_screen( bt, buffer, settings );

if ( settings->israw ) /* no interaction in raw-mode */
continue;

strcpy( prevcmd, cmd ); /* backup current command */

/* get new command */
if ( !show_prompt(bt, cmd, prevcmd, buffer, settings) )
continue;

if ( KEY_QUIT == *cmd )
break;

if ( '\n' == *cmd ) /* restore previous command */
strcpy( cmd, prevcmd );

do_command( &bt, cmd, prevcmd, buffer, settings );

}

putchar('\n');

return true;
}

/*********************************************************//**
*
*************************************************************
*/
void buffer_dump( const Buffer *buffer )
{
size_t i = 0U;

if ( !buffer || !buffer->data)
return;

for (i=0U; i < buffer->len; i++)
putchar( (int)buffer->data );
fflush( stdout );

return;
}


/*********************************************************//**
*
*************************************************************
*/
void buffer_cleanup( Buffer *buffer )
{
if ( !buffer )
return;

if ( buffer->data ) {
free(buffer->data);
buffer->data = NULL;
}

memset( buffer, 0, sizeof(Buffer) );
return;
}

/*********************************************************//**
* Read into a Buffer structure the contents of a file with size up tp LONG_MAX bytes.
*************************************************************
*/
_Bool buffer_read_file_longmax( Buffer *buffer, const char *fname )
{
long int buflen, bufsize;
FILE *fp = NULL;

if ( !buffer || !fname || '\0' == *fname )
return false;

if ( -1 == (bufsize = filesize(fname)) || NULL == (fp = fopen(fname, "rb")) )
return false;

/* make sure our Buffer struct starts with zeroed fields */
memset( buffer, 0, sizeof(Buffer) );

/* allocate room in memory for our buffer->data (+1 for zero-terminator) */
buflen = bufsize / sizeof(Byte);
if ( NULL == (buffer->data = calloc( buflen+1, sizeof(Byte) )) )
goto ret_failure;

printf("Loading \"%s\"... ", fname);
buflen = fread( buffer->data, sizeof(Byte), buflen, fp);
if ( ferror(fp) )
goto ret_failure;

fclose(fp);
puts("\nDone!");

/* update fields in our Buffer structure */
strcpy( buffer->fname, fname );
buffer->len = buflen;
buffer->nrows = buffer->len/FMT_NCOLS + (buffer->len % FMT_NCOLS != 0 ?1 :0);
buffer->npages = buffer->nrows / FMT_PGLINES
+ (buffer->nrows % FMT_PGLINES != 0 ? 1 : 0 );

return true;

ret_failure:
if ( buffer->data )
free( buffer->data );
memset( buffer, 0, sizeof(buffer) );

if ( fp )
fclose(fp);
return false;
}

/*********************************************************//**
* Read contents of file of any size into the Buffer structure.
*************************************************************
*/
_Bool buffer_read_file( Buffer *buf, const char *fname, size_t chunklen )
{
size_t n; /* # of Bytes read from file to chunk*/
size_t buflen = chunklen; /* current length of our data buffer */
Byte *try = NULL; /* to test reallocs before apply 'em */
FILE *fp = NULL;

if ( !buf || !fname || '\0' == *fname || NULL == (fp=fopen(fname, "rb")) )
return false;

/* make sure our Buffer struct starts with zeroed fields */
memset( buf, 0, sizeof(Buffer) );

/* allocate ahead room for chunklen Bytes */
if ( NULL == (buf->data = calloc( buflen, sizeof(Byte) )) )
return false;

/* inform the user */
printf( "Loading \"%s\\n", fname );
printf( "(in chunks of %llu bytes)\n",
(unsigned long long)(chunklen * sizeof(Byte))
);
printf( "Bytes loaded so far: ");

/* read the file into our Buffer structure */
while ( !feof(fp) )
{
/* read data from file into the newely allocated part of the Buffer */
n = fread( &buf->data[buflen-chunklen], sizeof(Byte), chunklen, fp);
if (ferror(fp) || n < chunklen) {
goto ret_failure;
}

/* allocate ahead chunklen more Bytes */
buflen += chunklen;
if ( NULL == (try = realloc( buf->data, buflen * sizeof(Byte) )) )
goto ret_failure;
buf->data = try;

/* display bytes read so far */
NBS( printf("%llu", (unsigned long long)(buflen-chunklen) * sizeof(Byte)) );
}
putchar('\n');

if ( ferror(fp) )
goto ret_failure;
fclose(fp);

/* truncate buffer=>data to actual file length */
buflen -= (chunklen - n);
if (NULL == (try = realloc( buf->data, buflen * sizeof(Byte) )) )
goto ret_failure;
buf->data = try;

/* update fields in our Buffer structure */
strcpy( buf->fname, fname );
buf->len = buflen;
buf->nrows = buf->len / FMT_NCOLS + (buf->len % FMT_NCOLS != 0 ? 1 : 0);
buf->npages = buf->nrows / FMT_PGLINES
+ (buf->nrows % FMT_PGLINES != 0 ? 1 : 0 );

return true;

ret_failure:
if ( buf->data )
free( buf->data );
memset( buf, 0, sizeof(buf) );

if ( fp )
fclose(fp);
return false;
}

/*********************************************************//**
*
*************************************************************
*/
int main( int argc, char *argv[] )
{
_Bool success = false;
char tmpfname[ MAXINPUT ] = {'\0'};

/* our Buffer structure */
Buffer buffer = {
.fname = {'\0'},
.len=0U, .nrows=0U, .npages=0U,
// .bt=0U, .row=0U, .pg=0U,
.data = NULL /* ... the actual buffer */
};
/* our Settings structure */
Settings settings = {
.colorize = true,
.charset = FMT_ASCII, /* ... plain ASCII */
.israw = false,
.unlimfsize = false
};

CONOUT_INIT();
CONOUT_SET_COLOR( FGCLR_NORMAL ); /* set console fg color */

/* parse the command line */
if ( 1 == argc ) /* no command line arguments */
strncpy(tmpfname, argv[0], MAXINPUT-1 );
else
strncpy(tmpfname, argv[1], MAXINPUT-1 );

/* read the file into the buffer */
success = (settings.unlimfsize)
? buffer_read_file( &buffer, tmpfname, 100*1024*1024 )
: buffer_read_file_longmax( &buffer, tmpfname );
if ( !success ) {
perror(NULL);
goto exit_failure;
}

/* list the file contents */
if ( !view_buffer( &buffer, &settings ) ) {
perror(NULL);
goto exit_failure;
}

buffer_cleanup( &buffer );

CONOUT_RESTORE();
exit( EXIT_SUCCESS );

exit_failure:
buffer_cleanup( &buffer );

CONOUT_RESTORE();
pressENTER();
exit( EXIT_FAILURE );
}


έγραψε:
EDIT: Έκδοση 0.26A - Public (αποκλειστικά για Alpha testing) : http://www.box.com/s/gl87fptnqq1a7cenn61n

[i]Οι hex viewers/editors (ή binary viewers/editors) δείχνουν τα ακριβή περιεχόμενα οποιουδήποτε αρχείου byte προς byte και συνήθως παρέχουν διάφορες low-level λειτουργίες.
Δυο χρήσιμα links:
1. http://en.wikipedia.org/wiki/Hex_editor
2. http://www.linfo.org/hex_editor.html

Παραθέτω παραπάνω τον κώδικα της έκδοσης 0.26A απλά και μόνο για να με βοηθήσουν όποιοι έχουν διάθεση εντοπίζοντας πιθανά προβλήματα, όσο εγώ θα σουλουπώνω τον μέχρι τώρα κώδικα. Όταν λέω να με βοηθήσετε δεν εννοώ στον κώδικα, αλλά ως απλοί χρήστες του προγράμματος... να δείτε δηλαδή αν λειτουργούν όλα σωστά μέχρι στιγμής.

Ο κώδικας είναι ακόμα σε ψιλο-άθλια κατάσταση. Θα ξεκινήσω τώρα να τον οργανώνω σωστά (επανεξέταση δομών, συναρτήσεων, μεταβλητών, κλπ) όσο ψάχνετε για πιθανά bugs. Στόχος είναι να διορθώσω οτιδήποτε στραβό υπάρχει μέχρι αυτή τη στιγμή, ώστε να είναι πολύ πιο εύκολο να προσθέσω νέα χαρακτηριστικά στη συνέχεια.

Η μέχρι τώρα λειτουργικότητα περιγράφεται εν συντομία στην οθόνη Help (πατήστε h + ENTER στην βασική οθόνη για να τη δείτε), ενώ η τρέχουσα κατάσταση της βασικής οθόνης αναλύεται στις 2 τελευταίες γραμμές της.

Η 1η γραμμή δίνει πληροφορίες για το ανοιχτό αρχείο: όνομα (τους τελευταίους 11 χαρακτήρες), μέγεθος σε Mbytes, μέγεθος σε γραμμές προβολής, μέγεθος σε σελίδες προβολής (και την τρέχουσα σελίδα μπροστά από τις συνολικές). Δείχνει επίσης το επιλεγμένο character set που χρησιμοποιείται για την προβολή των περιεχομένων ως χαρακτήρες στη δεξιά περιοχή: ASCII (εμφανίζονται όσοι χαρακτήρες έχουν ASCII code από 32 έως 127) ή xASCII (εμφανίζονται όσοι χαρακτήρες έχουν ASCII code από 32 έως 255 ... το χ σημαίνει eXtended :) ). Οι υπόλοιποι χαρακτήρες (non-printable) εμφανίζονται ως τελείες.

Η 2η γραμμή επικεντρώνεται περισσότερο στο byte (χαρακτήρα) που βρίσκεται ο δρομέας, δείχνοντας τα εξής:

στο 1ο κουτάκι δείχνει την θέση του τρέχοντος byte μέσα στο αρχείο...
Κώδικας: Επιλογή όλων
10δική θέση = 16αδική θέση / τελευταία θέση σε 16δική μορφή [ τρέχουσα γραμμή σε 16δική μορφή ]

στα 3 επόμενα κουτάκια δείχνει το ASCII code του τρέχοντος byte ως α) 10δική τιμή (unsigned και signed) β) 8αδική τιμή (unsigned) και γ) 2αδική τιμή.
Κώδικας: Επιλογή όλων
d(ec): unsigned, signed | o(ct): unsigned | unsigned

Το επόμενο κουτάκι δείχνει την τελευταία εντολή που πληκτρολογήσατε, ώστε πατώντας ENTER να την επαναλάβετε. Αυτό είναι πάρα πολύ χρήσιμο, επειδή το περιβάλλον είναι text-based και κυρίως επειδή ο κώδικας είναι γραμμένος σε στάνταρ C99 για να γίνεται compile χωρίς αλλαγές σε πολλές πλατφόρμες, άρα δεν υποστηρίζει άμεση μετακίνηση στην οθόνη (την επανασχεδιάζει σε ρυθμό κονσόλας μετά από κάθε σας εντολή.

Για παράδειγμα, μπορείτε να πληκτρολογήσετε την εντολή μετακίνησης στον επόμενο χαρακτήρα και κατόπιν να πατάτε απλά ENTER για να πηγαίνετε στους επόμενους. Οι εντολές μετακίνησης δέχονται προαιρετικά και ένα (θετικό) βήμα μετακίνησης. Οπότε αν θέλετε για παράδειγμα να μετακινείστε ας πούμε κατά 4 bytes τη φορά, πληκτρολογήστε την 1η φορά...
Κώδικας: Επιλογή όλων
>4 + ENTER
και όλες τις επόμενες φορές θα πατάτε σκέτο ENTER ;)

Όλα τα πλήκτρα των εντολών ορίζονται προς το παρόν στην αρχή του αρχείου: hexview.c, στο enum KeyCommand (και προφανώς μπορείτε να τα αλλάξετε :) ).

Σημειώστε επίσης πως η τρέχουσα γραμμή είναι πάντα η 1η γραμμή, δηλαδή γίνεται αυτόματη κύλιση ώστε η τρέχουσα γραμμή να εμφανίζεται πάντα πρώτη. Αυτό ξενίζει, αλλά είναι απαραίτητο για όταν είναι απενεργοποιημένα τα χρώματα (αλλιώς θα ήταν εξαιρετικά δύσκολο να δείτε σε ποιο byte βρίσκεστε ανά πάσα στιγμή... ενώ έτσι και σε συνδυασμό με το αστεράκι που εμφανίζεται στην τρέχουσα στήλη είναι σαφώς ευκολότερο). Για να δείτε τι εννοώ, πατήστε c + ENTER στην βασική οθόνη για να απενεργοποιήσετε τα χρώματα και θα καταλάβετε (πατήστε ξανά c + ENTER για να επαναφέρετε τα χρώματα).

Προς το παρόν το Theme των χρωμάτων είναι μονάχα για κονσόλες με μαύρο φόντο (θα βρείτε τα σχετικά #define στο αρχείο: hexview.h, αν θελήσετε να πειραματιστείτε με τα εμφανιζόμενα χρώματα).

Έχει μερικά ακόμα χρήσιμα πραγματάκια, δείτε την οθόνη Help και πειραματιστείτε και ρωτήστε ότι θέλετε. Σε αυτήν την έκδοση έχω απενεργοποιήσει την παράμετρο -raw στη γραμμή εντολών.

Η διαδικασία μεταγλώττισης παραμένει ίδια...

Unix/Linux
Κώδικας: Επιλογή όλων
gcc hexview.c -o hexview

Windows
Κώδικας: Επιλογή όλων
gcc hexview.c -o hexview.exe

Αν το τρέξετε χωρίς όνομα αρχείου στη γραμμή εντολών, τότε ανοίγει τον εαυτό του. Μπορείτε να ανοίξετε άλλο αρχείο και από μέσα από το πρόγραμμα, με την εντολή:
Κώδικας: Επιλογή όλων
ffilename
χωρίς κενά διαστήματα μετά το f.

Παραθέτω και 3 screen-shots από αυτή την έκδοση (ανοίξτε το spoiler)

Spoiler: show
Εικόνα

Εικόνα

Εικόνα



έγραψε:

Έκδοση 0.1Α: http://ideone.com/ttnNJ

Παραθέτω κώδικα από έναν πολύ απλό δεκαεξαδικό viewer αρχείων (HexViewer): http://ideone.com/ttnNJ

Χωρίς παράμετρο στη γραμμή εντολών, ρωτάει ποιο αρχείο να ανοίξει και το δείχνει σελιδοποιημένο, όπως φαίνεται στην παρακάτω εικόνα (από Windows). Μπορείτε όμως να περάστε το όνομα του αρχείου και απευθείας στη γραμμή εντολών, π.χ...

Κώδικας: Επιλογή όλων

./a.out a.out


Εικόνα

Επειδή το πρόγραμμα δεν παρέχει μετακίνηση μέσα στο αρχείο που δείχνει (πέρα από την σειριακή του εμφάνιση, ανά σελίδα) μπορείτε να χρησιμοποιήστε ως 1η παράμετρο στην γραμμή εντολών του το "-raw" και κατόπιν το όνομα του αρχείου που θέλετε να ανοίξει. Κάνοντας το κατόπιν pipe στο less (ή στο more, ή σε όποιον άλλον file viewer κονσόλας χρησιμοποιείτε) έχετε έναν λειτουργικότατο hex-viewer...

Κώδικας: Επιλογή όλων

./a.out -raw a.out | less

Η παραπάνω εικόνα δείχνει το εκτελέσιμο αρχείο του προγράμματος περασμένο στον εαυτό του, σε Windows. Όσοι έχετε ασχοληθεί με την εσωτερική δομή αρχείων στα Windows, μπορείτε να διακρίνετε στο "Chars area" το χαρακτηριστικό "MZ" στα 2 πρώτα bytes, που υποδηλώνουν πως πρόκειται για Win32 εκτελέσιμο (το οποίο π.χ. δεν τρέχει σε DOS). Λίγο πιο κάτω μπορείτε να δείτε τον χαρακτηριστικό PE header που υπάρχει σε όλα τα εκτελέσιμα των Windows. Στο Linux σε πλατφόρμες x86 τα αναγνωριστικά bytes των εκτελέσιμων γράφουν "ELF".

Αν έχω όρεξη μπορεί να του προσθέσω PageUp και PageDown λειτουργικότητα :P

Μεταγλώττιση:
Κώδικας: Επιλογή όλων
gcc -Wall -Wextra hexview.c -o hexview

Χρήση:
Κώδικας: Επιλογή όλων
hexview [-raw] [filename]


ΥΓ. Στη γραμμή εργαλείων των Windows δεν υπάρχει ο viewer less. Μπορείτε να κατεβάσετε μια Windows εκδοχή του από εδώ. Εναλλακτικά, μπορείτε να κατεβάσετε ολόκληρα πακέτα με unix-like εργαλεία γραμμής εντολών για Windows, όπως το GnuWin, ένα παλαιότερο υποσύνολό του, τα UnixUtils ή αν θέλετε έναν πλήρη Linux emulator στα Windows, το Cygwin.

Τελευταία επεξεργασία από migf1 και 17 Απρ 2012, 15:06, έχει επεξεργασθεί 15 φορά/ες συνολικά
Go under the hood with C: Pointers, Strings, Linked Lists
Άβαταρ μέλους
migf1
powerTUX
powerTUX
 
Δημοσιεύσεις: 2082
Εγγραφή: 03 Ιουν 2011, 16:32
Εκτύπωση

Re: ANSI C: File HexViewer

Δημοσίευσηαπό cyberpython » 22 Φεβ 2012, 14:39

:clap:
Κοινότητα ΕΛ/ΛΑΚ Οικονομικού Πανεπιστημίου Αθηνών / Ubuntu-gr / My Web Log
Επίπεδο Γνώσεων Linux: Μέτριο, Προγραμματισμός: Ναι, Aγγλικά: Καλά
Λειτουργικό : Ubuntu 10.04 - 32bits
Η/Υ : Intel Core2 4400@2 GHz / 2GB DDR2 RAM / GeForce 8400 GS 512MB / Creative SB Audigy SE
Άβαταρ μέλους
cyberpython
seniorTUX
seniorTUX
 
Δημοσιεύσεις: 733
Εγγραφή: 14 Μάιος 2008, 13:22
Εκτύπωση

Re: ANSI C: File HexViewer

Δημοσίευσηαπό migf1 » 22 Φεβ 2012, 16:22

:)

Μάλλον θα του βάλω και δυνατότητα μετακίνησης στο εμφανιζόμενο αρχείο. Aν γραφτεί σωστά ο κώδικας μετακίνησης, τότε θα του είναι αδιάφορο αν η μετακίνηση θα γίνεται βάσει γραμμής, θέσης ή σελίδας.

Πιο χρονοβόρο θα είναι να γράψω κώδικα για την υποστήριξη των εντολών μετακίνησης παρά για την ίδια την μετακίνηση :lol:
Go under the hood with C: Pointers, Strings, Linked Lists
Άβαταρ μέλους
migf1
powerTUX
powerTUX
 
Δημοσιεύσεις: 2082
Εγγραφή: 03 Ιουν 2011, 16:32
Εκτύπωση

Re: ANSI C: File HexViewer

Δημοσίευσηαπό migf1 » 24 Φεβ 2012, 13:55

Ξεκίνησα να του βάζω δυνατότητες μετακίνησης, αλλά και υποστήριξη χρωμάτων για πιο ευανάγνωστη έξοδο.

Εικόνα
Εικόνα

"Γλυκάθηκα" όμως και σκέφτομαι να του προσθέσω κι άλλα πράγματα, π.χ. δυνατότητα αναζήτησης. Προς το παρόν ο κώδικας δεν είναι έτοιμος για δημοσίευση. Απλά ενημερωτικά έβαλα τα παραπάνω screen-shots.

Τα χρώματα στην 1η εικόνα διαχωρίζουν τα bytes που αντιστοιχούν σε εκτυπώσιμους χαρακτήρες (ανοιχτό γκρι), από τα υπόλοιπα, τα οποία με τη σειρά τους διαχωρίζονται σε εκείνα που είναι μηδενισμένα (σκούρο γκρι) και σε εκείνα που δεν είναι μηδενισμένα (σκούρο κίτρινο). Το theme αυτό είναι για κονσόλες με μαύρο φόντο, πράγμα που σημαίνει πως πρέπει να φτιάξω και theme για κονσόλες με ανοιχτό φόντο (άσπρο ή ανοιχτό γκρι)... ευελπιστώ πως με αυτά τα 2 themes θα καλυφθούν και περιπτώσεις που χρησιμοποιούν φόντο άλλου χρώματος, αν τις διαχωρίσουμε νοητικά σε "σκούρα" και "ανοιχτά" backgrounds.

Πάντως δεν σκοπεύω να το κάνω full-bllown hex-viewer (βλέποντας και κάνοντας).
Go under the hood with C: Pointers, Strings, Linked Lists
Άβαταρ μέλους
migf1
powerTUX
powerTUX
 
Δημοσιεύσεις: 2082
Εγγραφή: 03 Ιουν 2011, 16:32
Εκτύπωση

Re: ANSI C: File HexViewer

Δημοσίευσηαπό migf1 » 29 Φεβ 2012, 18:47

Έκδοση 0.26Α με πάρα πολλές αλλαγές στο αρχικό ποστ: http://forum.ubuntu-gr.org/viewtopic.ph ... 43#p231743
Όσοι έχετε διάθεση να το κάνετε beta-test ως απλοί χρήστες, σε ότι υλοποιεί μέχρι στιγμής, please do so! (διαβάστε το παραπάνω link).
Go under the hood with C: Pointers, Strings, Linked Lists
Άβαταρ μέλους
migf1
powerTUX
powerTUX
 
Δημοσιεύσεις: 2082
Εγγραφή: 03 Ιουν 2011, 16:32
Εκτύπωση

Re: ANSI C: File HexViewer

Δημοσίευσηαπό linuxs » 29 Φεβ 2012, 19:55

Ίσως να αναφέρεις στο αρχικό ποστ τι ακριβώς είναι αυτό με λίγες γραμμές ώστε να το καταλάβω και εγώ(και όποιος άλλος έχει δυσκολία)?
Αν το πρόβλημά μας επιλυθεί. Επιλέγουμε το θέμα που βοήθησε στην επίλυση και πατάμε το κουμπάκι Εικόνα.
Γνώσεις ⇛ Linux: Μέτριο┃Προγραμματισμός: C┃Αγγλικά: Καλά
Λειτουργικό ⇛ Linux Ubuntu 10.4 LTS
Προδιαγραφές ⇛ Intel Pentium @T4500 2.3GHz│ 512GB VRAM│ 500 HDD│ ATI RADEON HD545v 512 MB │ Screen: 15.6''
Άβαταρ μέλους
linuxs
daemonTUX
daemonTUX
 
Δημοσιεύσεις: 1060
Εγγραφή: 02 Ιούλ 2010, 13:19
Τοποθεσία: GR
IRC: linuxs
Εκτύπωση

Re: ANSI C: File HexViewer

Δημοσίευσηαπό Ilias95 » 29 Φεβ 2012, 23:44

Στα γρήγορα.

Κατά το compile πήρα:
Κώδικας: Επιλογή όλων
ilias@ilias-pc:~/hex$ gcc hexview.c -o hexview
hexview.c: In function ‘view_row’:
hexview.c:457:10: προειδοποίηση: assignment makes integer from pointer without a cast [enabled by default]
hexview.c:458:2: προειδοποίηση: passing argument 1 of ‘printf’ makes pointer from integer without a cast [enabled by default]
/usr/include/stdio.h:359:12: σημείωση: expected ‘const char * __restrict__’ but argument is of type ‘int’
hexview.c:458:2: προειδοποίηση: format not a string literal and no format arguments [-Wformat-security]
hexview.c:477:12: προειδοποίηση: assignment makes integer from pointer without a cast [enabled by default]
hexview.c:478:4: προειδοποίηση: passing argument 1 of ‘printf’ makes pointer from integer without a cast [enabled by default]
/usr/include/stdio.h:359:12: σημείωση: expected ‘const char * __restrict__’ but argument is of type ‘int’
hexview.c:478:4: προειδοποίηση: format not a string literal and no format arguments [-Wformat-security]
hexview.c:484:12: προειδοποίηση: assignment makes integer from pointer without a cast [enabled by default]
hexview.c:485:4: προειδοποίηση: passing argument 1 of ‘printf’ makes pointer from integer without a cast [enabled by default]
/usr/include/stdio.h:359:12: σημείωση: expected ‘const char * __restrict__’ but argument is of type ‘int’
hexview.c:485:4: προειδοποίηση: format not a string literal and no format arguments [-Wformat-security]
hexview.c:491:12: προειδοποίηση: assignment makes integer from pointer without a cast [enabled by default]
hexview.c:492:4: προειδοποίηση: passing argument 1 of ‘printf’ makes pointer from integer without a cast [enabled by default]
/usr/include/stdio.h:359:12: σημείωση: expected ‘const char * __restrict__’ but argument is of type ‘int’
hexview.c:492:4: προειδοποίηση: format not a string literal and no format arguments [-Wformat-security]
hexview.c:511:12: προειδοποίηση: assignment makes integer from pointer without a cast [enabled by default]
hexview.c:512:4: προειδοποίηση: passing argument 1 of ‘printf’ makes pointer from integer without a cast [enabled by default]
/usr/include/stdio.h:359:12: σημείωση: expected ‘const char * __restrict__’ but argument is of type ‘int’
hexview.c:512:4: προειδοποίηση: format not a string literal and no format arguments [-Wformat-security]
hexview.c:515:12: προειδοποίηση: assignment makes integer from pointer without a cast [enabled by default]
hexview.c:516:4: προειδοποίηση: passing argument 1 of ‘printf’ makes pointer from integer without a cast [enabled by default]
/usr/include/stdio.h:359:12: σημείωση: expected ‘const char * __restrict__’ but argument is of type ‘int’
hexview.c:516:4: προειδοποίηση: format not a string literal and no format arguments [-Wformat-security]
hexview.c:519:12: προειδοποίηση: assignment makes integer from pointer without a cast [enabled by default]
hexview.c:520:4: προειδοποίηση: passing argument 1 of ‘printf’ makes pointer from integer without a cast [enabled by default]
/usr/include/stdio.h:359:12: σημείωση: expected ‘const char * __restrict__’ but argument is of type ‘int’
hexview.c:520:4: προειδοποίηση: format not a string literal and no format arguments [-Wformat-security]
ilias@ilias-pc:~/hex$


Επίσης υπάρχει μήπως κάποιο πρόβλημα με το -raw argument;
Κώδικας: Επιλογή όλων
ilias@ilias-pc:~/hex$ ls
con_color.h hexview hexview.c hexview.h test1.py
ilias@ilias-pc:~/hex$ ./hexview -raw hexview
No such file or directory
press ENTER...
ilias@ilias-pc:~/hex$ ./hexview -raw test1.py
No such file or directory
press ENTER...


Δεν πρόλαβα να κάνω δοκιμές. Θα κάνω αργότερα με διάφορα αρχεία.
Αλλά πες μας αν θες κάποια σημεία που πρέπει να προσέξουμε αν δουλεύουν σωστά.
Ilias95
saintTUX
saintTUX
 
Δημοσιεύσεις: 1548
Εγγραφή: 29 Απρ 2011, 23:26
Εκτύπωση

Re: ANSI C: File HexViewer

Δημοσίευσηαπό migf1 » 29 Φεβ 2012, 23:52

Ναι τις είδα κι εγώ τις προειδοποιήσεις πριν από λίγο στο ubuntu... δεν ξέρω γιατί τις βγάζει, τρέχει κανονικά όμως το πρόγραμμα (στα Windows δεν βγάζει τέτοιες προειδοποιήσεις πάντως).

Για την -raw το έγραψα ήδη Ηλία πως το κατάργησα (προσωρινά) σε αυτή την έκδοση. Διάβασες το 1ο πόστ αυτού του νήματος; Έγραψα αρκετά πράγματα σήμερα το μεσημέρι.

@linuxs: Οι hex viewers/editors (ή binary viewers/editors) δείχνουν τα ακριβή περιεχόμενα οποιουδήποτε αρχείου byte προς byte και συνήθως παρέχουν διάφορες low-level λειτουργίες.

Δυο χρήσιμα links:
1. http://en.wikipedia.org/wiki/Hex_editor
2. http://www.linfo.org/hex_editor.html

Θα τα βάλω και στο αρχικό ποστ, thanks!
Go under the hood with C: Pointers, Strings, Linked Lists
Άβαταρ μέλους
migf1
powerTUX
powerTUX
 
Δημοσιεύσεις: 2082
Εγγραφή: 03 Ιουν 2011, 16:32
Εκτύπωση

Re: ANSI C: File HexViewer

Δημοσίευσηαπό Ilias95 » 01 Μαρ 2012, 00:02

migf1 έγραψε:Για την -raw το έγραψα ήδη Ηλία πως το κατάργησα (προσωρινά) σε αυτή την έκδοση. Διάβασες το 1ο πόστ αυτού του νήματος; Έγραψα αρκετά πράγματα σήμερα το μεσημέρι.

Ουπς, ναι συγγνώμη. :oops: Το έκανα λίγο βιαστικά γι' αυτό μου ξέφυγαν.
Θα δοκιμάσω με κάποια αρχεία μόλις προλάβω και θα κάνω ένα feedback.
Ilias95
saintTUX
saintTUX
 
Δημοσιεύσεις: 1548
Εγγραφή: 29 Απρ 2011, 23:26
Εκτύπωση

Re: ANSI C: File HexViewer

Δημοσίευσηαπό migf1 » 01 Μαρ 2012, 00:23

Thanks! Χαλαρά, δεν υπάρχει βιασύνη.

Εγώ εντόπισα ήδη ένα πρόβλημα με αρχείο μεγέθους 1.9Gb. Όταν είναι compiled με mingw-gcc τότε κρασάρει. Όταν είναι compiled με Pelles-C, τότε δεν κρασάρει, αλλά έφτασε στο 1.6Gb και μετά δεν μπορούσε να κάνει allocate άλλη μνήμη... προφανώς και στς 2 περιπτώσεις δεν είχα τόσο ελεύθερη διαθέσιμη μνήμη (δεν έπαιξα με τις ρυθμίσεις τις εικονικής μνήμης πάντως).

Στη δομή Settings, υπάρχει ένα boolean πεδίο: unlimfsize που το έχω ίσο με FALSE. Όταν αυτό το πεδίο είναι FALSE, τα αρχεία διαβάζονται με την ρουτίνα: _Bool buffer_read_file_longmax( Buffer *buffer, const char *fname ) η οποία έχει όριο μεγέθους τα LLONG_MAX bytes (αυτά συνήθως είναι 2Gb). Όταν το πεδίο unlimfsize τεθεί ίσο με TRUE, τότε το διάβασμα των αρχείων γίνεται με την ρουτίνα: _Bool buffer_read_file( Buffer *buf, const char *fname, size_t chunklen ) η οποία δεν θέτει κανένα όριο στο μέγεθος του αρχείου. Αν δείτε στον κώδικα, την καλώ με chunklen = 100*1024*1024 που σημαίνει πως διαβάζει το αρχείο σε τμήματα των 100mbytes, μέχρι να διαβαστεί όλο ή να τελειώσει η μνήμη.

Οπότε αν θέλετε να δοκιμάσετε με αρχεία μεγαλύτερα των 2Gb, θέστε το πεδίο unlimfsize ίσο με TRUE (στην αρχή της main() θα το βρείτε, στην αρχικοποίηση της δομής Settings).

Υπάρχει επίσης ένα ακόμα θέμα με τον παρόντα κώδικα. Παρόλο που οι συναρτήσεις είναι φτιαγμένες να πιάνουν πιθανά exceptions και να μην κρασάρουν, εντούτοις δεν χρησιμοποιώ πάντα (ακόμα) τις τιμές επιστροφής τους, οπότε υπάρχει περίπτωση να μπει σε infinite loop, αν αποτύχει κάποια συνάρτηση (αυτά θα τα φτιάξω).

Σε γενικές γραμμές, προσπαθήστε να κάνετε το πρόγραμμα να ζοριστεί ή να κρασάρει, πιέζοντας στα όρια τις έως τώρα υλοποιημένες του λειτουργίες.
Go under the hood with C: Pointers, Strings, Linked Lists
Άβαταρ μέλους
migf1
powerTUX
powerTUX
 
Δημοσιεύσεις: 2082
Εγγραφή: 03 Ιουν 2011, 16:32
Εκτύπωση

Επόμενο

Επιστροφή στο Ανάπτυξη Λογισμικού / Αλγόριθμοι