toaruos/apps/hexify.c
2021-08-31 16:50:45 +09:00

201 lines
4.8 KiB
C

/* vim: tabstop=4 shiftwidth=4 noexpandtab
* This file is part of ToaruOS and is released under the terms
* of the NCSA / University of Illinois License - see LICENSE.md
* Copyright (C) 2018 K. Lange
*
* hexify - Convert binary to hex.
*
* This is based on the output of xxd.
* Does NOT a hex-to-bin option - something to consider.
*/
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
void print_line(unsigned char * buf, unsigned int width, unsigned int sizer, unsigned int offset) {
fprintf(stdout, "%08x: ", sizer);
for (unsigned int i = 0; i < width; ) {
if (i >= offset) {
fprintf(stdout, " ");
} else {
fprintf(stdout, "%02x", buf[i]);
}
i++;
if (i == width) break; /* in case of odd width */
if (i >= offset) {
fprintf(stdout, " ");
} else {
fprintf(stdout, "%02x ", buf[i]);
}
i++;
}
fprintf(stdout, " ");
for (unsigned int i = 0; i < width; i++) {
if (i >= offset) {
fprintf(stdout, " ");
} else {
if (isprint(buf[i])) {
fprintf(stdout, "%c", buf[i]);
} else {
fprintf(stdout, ".");
}
}
}
fprintf(stdout, "\n");
}
static int stoih(int w, char c[w], unsigned int *out) {
*out = 0;
for (int i = 0; i < w; ++i) {
(*out) <<= 4;
if (c[i] >= '0' && c[i] <= '9') {
*out |= (c[i] - '0');
} else if (c[i] >= 'A' && c[i] <= 'F') {
*out |= (c[i] - 'A' + 0xA);
} else if (c[i] >= 'a' && c[i] <= 'f') {
*out |= (c[i] - 'a' + 0xA);
} else {
*out = 0;
return 1;
}
}
return 0;
}
int main(int argc, char * argv[]) {
unsigned int width = 16; /* TODO make configurable */
int opt;
int direction = 0;
while ((opt = getopt(argc, argv, "?w:d")) != -1) {
switch (opt) {
default:
case '?':
fprintf(stderr, "%s: convert to/from hexadecimal dump\n", argv[0]);
return 1;
case 'w':
width = atoi(optarg);
break;
case 'd':
direction = 1;
break;
}
}
FILE * f;
char * name;
if (optind < argc) {
f = fopen(argv[optind], "r");
name = argv[optind];
if (!f) {
fprintf(stderr, "%s: %s: %s\n", argv[0], argv[optind], strerror(errno));
return 1;
}
} else {
name = "[stdin]";
f = stdin;
}
if (direction == 0) {
/* Convert to hexadecimal */
unsigned int sizer = 0;
unsigned int offset = 0;
unsigned char buf[width];
while (!feof(f)) {
unsigned int r = fread(buf+offset, 1, width-offset, f);
offset += r;
if (offset == width) {
print_line(buf, width, sizer, offset);
offset = 0;
sizer += width;
}
}
if (offset != 0) {
print_line(buf, width, sizer, offset);
}
} else {
/* Convert from hexify's output format */
unsigned int eoffset = 0;
unsigned int lineno = 1;
while (!feof(f)) {
/* Read offset */
char offset_bytes[8];
fread(&offset_bytes, 1, 8, f);
/* Convert offset for verification */
unsigned int offset;
if (stoih(8, offset_bytes, &offset)) {
fprintf(stderr, "%s: %s: syntax error (bad offset) on line %d\n", argv[0], name, lineno);
fprintf(stderr, "offset bytes: %8s\n", offset_bytes);
return 1;
}
if (offset != eoffset) {
fprintf(stderr, "%s: %s: offset mismatch on line %d\n", argv[0], name, lineno);
fprintf(stderr, "expected 0x%x, got 0x%x\n", offset, eoffset);
return 1;
}
/* Read ": " */
char tmp[2];
fread(&tmp, 1, 2, f);
if (tmp[0] != ':' || tmp[1] != ' ') {
fprintf(stderr, "%s: %s: syntax error (unexpected characters after offset) on line %d\n", argv[0], name, lineno);
return 1;
}
/* Read [width] characters */
for (unsigned int i = 0; i < width; ) {
unsigned int byte = 0;
for (unsigned int j = 0; i < width && j < 2; ++j, ++i) {
fread(&tmp, 1, 2, f);
if (tmp[0] == ' ' && tmp[1] == ' ') {
/* done; return */
return 0;
}
if (stoih(2, tmp, &byte)) {
fprintf(stderr, "%s: %s: syntax error (bad byte) on line %d\n", argv[0], name, lineno);
fprintf(stderr, "byte bytes: %2s\n", tmp);
return 1;
}
fwrite(&byte, 1, 1, stdout);
}
/* Read space */
fread(&tmp, 1, 1, f);
if (tmp[0] != ' ') {
fprintf(stderr, "%s: %s: syntax error (unexpected characters after byte) on line %d\n", argv[0], name, lineno);
fprintf(stderr, "unexpected character: %c\n", tmp[0]);
return 1;
}
}
fread(&tmp, 1, 1, f);
if (tmp[0] != ' ') {
fprintf(stderr, "%s: %s: syntax error (unexpected characters after bytes) on line %d\n", argv[0], name, lineno);
}
/* Read correct number of characters, plus line feed */
char tmp2[width+2];
fread(&tmp2, 1, width+1, f);
tmp2[width+1] = '\0';
if (tmp2[width] != '\n') {
fprintf(stderr, "%s: %s: syntax error: expected end of line, got garbage on line %d\n", argv[0], name, lineno);
fprintf(stderr, "eol data: %s\n", tmp2);
}
lineno++;
eoffset += width;
}
}
return 0;
}