Skip to content

Instantly share code, notes, and snippets.

@Wouterr0
Last active October 23, 2021 10:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Wouterr0/af3c4423c828f695ecafca5ea5492ac4 to your computer and use it in GitHub Desktop.
Save Wouterr0/af3c4423c828f695ecafca5ea5492ac4 to your computer and use it in GitHub Desktop.
Hexdump file to stdout
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <errno.h>
#include <math.h>
#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)
#define USAGE_HEADER "\nUsage:\n"
#define USAGE_SEPARATOR "\n"
#define max(a,b) (((a) > (b)) ? (a) : (b))
#define min(a,b) (((a) < (b)) ? (a) : (b))
typedef unsigned char byte;
static void usage(char* progname)
{
FILE* out = stdout;
fputs(USAGE_HEADER, out);
fprintf(out, " %s <file>\n", progname);
fputs(USAGE_SEPARATOR, out);
fputs("Hexdump file contents.\n", out);
exit(EXIT_SUCCESS);
}
char getcolorcode(byte datum)
{
if (datum == 0) return '8';
else if (datum > 0 && datum < 32 || datum == 127) return '5';
else if (datum >= 32 && datum < 127) return '2';
else if (datum > 127) return '6';
else return '9';
}
void hexdump(byte* blob, size_t size)
{
const unsigned int address_length = max(ceil(log((double)size) / log(16.0)), 6);
byte last_data_block[16];
bool indicated_truncation = false;
for (unsigned int block_start = 0; block_start < size; block_start += 16) {
if (block_start + 16 >= size || block_start == 0 || memcmp(last_data_block, blob + block_start, 16)) {
char hex_chars[16 * 12 + 1];
memset(hex_chars, '\0', 16 * 12);
char printable_chars[16 * 10 + 1];
memset(printable_chars, '\0', 16 * 10);
unsigned int hex_i = 0; // independent from i because of the space in the middle
for (unsigned int i = 0; i < 16; i++) {
if (i + block_start < size) {
byte datum = blob[block_start + i];
char colorcode = getcolorcode(datum);
hex_chars[sprintf(hex_chars + hex_i, "\033[38;5;%cm%02x", colorcode, datum) + hex_i] = ' ';
sprintf(printable_chars + i * 10, "\033[38;5;%cm%c", colorcode, (datum >= 32 && datum < 127) ? datum : '.');
}
else {
// if the end of the data has been reached fill the rest with spaces
hex_chars[sprintf(hex_chars + hex_i, "\033[38;5;9m ") + hex_i] = ' ';
}
if (i == 8) {
hex_i += 13;
hex_chars[hex_i - 1] = ' ';
}
else {
hex_i += 12;
}
}
hex_chars[16 * 12] = '\0';
memcpy(last_data_block, blob + block_start, 16);
indicated_truncation = false;
printf("\033[0m%.*x %-48s\033[0m |%s\033[0m|\n", address_length, block_start, hex_chars, printable_chars);
}
else if (!indicated_truncation) {
puts("*");
indicated_truncation = true;
}
}
}
int main(int argc, char** argv)
{
byte *data = NULL;
FILE *fp = NULL;
if (argc < 2 || argc > 2) {
fputs("Incorrect number of arguments supplied.\n", stderr);
usage(argv[0]);
}
fp = fopen(argv[1], "rb");
if (!fp) {
fprintf(stderr, "Failed to open file %s: %s\n", argv[1], strerror(errno));
exit(EXIT_FAILURE);
}
fseek(fp, 0L, SEEK_END);
long file_size = ftell(fp);
fseek(fp, 0L, SEEK_SET);
data = malloc(file_size);
if (!data) {
fputs("Failed to malloc\n", stderr);
exit(EXIT_FAILURE);
}
fread(data, sizeof(char), file_size, fp);
hexdump(data, file_size);
return 0;
}
@Wouterr0
Copy link
Author

Wouterr0 commented Jul 6, 2021

Yet Another Simple File Hexdump Utility
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment