Last active
October 23, 2021 10:19
-
-
Save Wouterr0/af3c4423c828f695ecafca5ea5492ac4 to your computer and use it in GitHub Desktop.
Hexdump file to stdout
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Yet Another Simple File Hexdump Utility
