Browse Source

Add reverse (hex-bin) mode to hexify

K. Lange 2 years ago
parent
commit
df64c9db41
1 changed files with 141 additions and 16 deletions
  1. 141 16
      apps/hexify.c

+ 141 - 16
apps/hexify.c

@@ -10,6 +10,9 @@
  */
 #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);
@@ -43,32 +46,154 @@ void print_line(unsigned char * buf, unsigned int width, unsigned int sizer, uns
 	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[]) {
-	FILE * f;
 	unsigned int width = 16; /* TODO make configurable */
-	if (argc > 1) {
-		f = fopen(argv[1], "r");
-		if (!f) return 1;
+	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));
+		}
 	} else {
+		name = "[stdin]";
 		f = stdin;
 	}
 
-	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 (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 == width) {
+		if (offset != 0) {
 			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;
 }