227 lines
5 KiB
C
227 lines
5 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdarg.h>
|
|
#include <inttypes.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <sys/stat.h>
|
|
#include <errno.h>
|
|
|
|
#define ZXDUMP_STRIDE_LINE 16
|
|
#define ZXDUMP_STRIDE_GROUP 2
|
|
#define ZXDUMP_CHARSET_LEN 64
|
|
|
|
static uint32_t zx_charset[ZXDUMP_CHARSET_LEN] = {
|
|
0x0020, 0x2598, 0x259d, 0x2580, 0x2596, 0x258c, 0x259e, 0x259b,
|
|
0x2592, '.', '.', '"', 0x00a3, '$', ':', '?',
|
|
'(', ')', '>', '<', '=', '+', '-', '*',
|
|
'/', ';', ',', '.', '0', '1', '2', '3',
|
|
'4', '5', '6', '7', '8', '9', 'A', 'B',
|
|
'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
|
|
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R',
|
|
'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
|
};
|
|
|
|
static void usage(int argc, char **argv, char *message, ...) {
|
|
if (message != NULL) {
|
|
va_list args;
|
|
|
|
va_start(args, message);
|
|
vfprintf(stderr, message, args);
|
|
fputc('\n', stderr);
|
|
va_end(args);
|
|
}
|
|
|
|
fprintf(stderr, "usage: %s file\n", argv[0]);
|
|
exit(1);
|
|
}
|
|
|
|
static inline size_t utf8_encode(uint8_t *buf, uint32_t codepoint) {
|
|
if ((codepoint & 0x007f) == codepoint) {
|
|
buf[0] = codepoint & 0x007f;
|
|
|
|
return 1;
|
|
} else if ((codepoint & 0x07ff) == codepoint) {
|
|
buf[0] = 0xc0 | ((codepoint & 0x07c0) >> 6);
|
|
buf[1] = 0x80 | (codepoint & 0x003f);
|
|
|
|
return 2;
|
|
} else if ((codepoint & 0xffff) == codepoint) {
|
|
buf[0] = 0xe0 | ((codepoint & 0xf000) >> 12);
|
|
buf[1] = 0x80 | ((codepoint & 0x0fc0) >> 6);
|
|
buf[2] = 0x80 | (codepoint & 0x003f);
|
|
|
|
return 3;
|
|
} else {
|
|
buf[0] = 0xf0 | ((codepoint & 0x1c0000) >> 18);
|
|
buf[1] = 0x80 | ((codepoint & 0x03f000) >> 12);
|
|
buf[2] = 0x80 | ((codepoint & 0x000fc0) >> 6);
|
|
buf[3] = 0x80 | (codepoint & 0x00003f);
|
|
|
|
return 4;
|
|
}
|
|
}
|
|
|
|
static inline int zx_putchar(uint8_t c) {
|
|
uint8_t sequence[4];
|
|
size_t len = utf8_encode(sequence, zx_charset[c]);
|
|
|
|
if (c > 63) {
|
|
fprintf(stderr, "What the fuck? Got c %02x\n", c);
|
|
}
|
|
|
|
if (fwrite(sequence, len, 1, stdout) < 1) {
|
|
goto error_io;
|
|
}
|
|
|
|
return 0;
|
|
|
|
error_io:
|
|
return -1;
|
|
}
|
|
|
|
static ssize_t dump_line(off_t offset, void *buf, size_t len, int tty) {
|
|
size_t i;
|
|
|
|
if (printf("%08zx: ", offset) < 0) {
|
|
goto error_io;
|
|
}
|
|
|
|
for (i=0; i<len; i++) {
|
|
if (i > 0 && (i % ZXDUMP_STRIDE_GROUP) == 0) {
|
|
if (putchar(' ') < 0) {
|
|
goto error_io;
|
|
}
|
|
}
|
|
|
|
if (printf("%02x", ((uint8_t *)buf)[offset+i]) < 0) {
|
|
goto error_io;
|
|
}
|
|
}
|
|
|
|
if (printf(" ") < 0) {
|
|
goto error_io;
|
|
}
|
|
|
|
for (i=0; i<len; i++) {
|
|
uint8_t c = ((uint8_t *)buf)[offset+i];
|
|
|
|
if (c <= 0x3f) {
|
|
if (zx_putchar(c) < 0) {
|
|
goto error_io;
|
|
}
|
|
} else if (c >= 0xa0 && c <= 0xbf) {
|
|
if (tty && printf("\033[7m") < 0) {
|
|
goto error_io;
|
|
}
|
|
|
|
if (zx_putchar(c - 0xa0) < 0) {
|
|
goto error_io;
|
|
}
|
|
|
|
if (tty && printf("\033[27m") < 0) {
|
|
goto error_io;
|
|
}
|
|
} else {
|
|
if (putchar('.') < 0) {
|
|
goto error_io;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (putchar('\n') < 0) {
|
|
goto error_io;
|
|
}
|
|
|
|
return fflush(stdout);
|
|
|
|
error_io:
|
|
return -1;
|
|
}
|
|
|
|
static ssize_t dump_fd(int fd) {
|
|
void *buf;
|
|
ssize_t total = 0;
|
|
struct stat st;
|
|
|
|
if (fstat(fd, &st) < 0) {
|
|
goto error_fstat;
|
|
}
|
|
|
|
if ((buf = malloc(st.st_blksize)) == NULL) {
|
|
goto error_malloc;
|
|
}
|
|
|
|
while (1) {
|
|
ssize_t len, i;
|
|
off_t offset = 0;
|
|
|
|
if ((len = read(fd, buf, st.st_blksize)) < 0) {
|
|
goto error_read;
|
|
} else if (len == 0) {
|
|
break;
|
|
}
|
|
|
|
for (i=0; i<len; i+=ZXDUMP_STRIDE_LINE) {
|
|
size_t left = len - i,
|
|
linesz = left < ZXDUMP_STRIDE_LINE? left: ZXDUMP_STRIDE_LINE;
|
|
|
|
if (dump_line(offset, buf, linesz, isatty(fileno(stdout))) < 0) {
|
|
goto error_dump_line;
|
|
}
|
|
|
|
offset += linesz;
|
|
total += linesz;
|
|
}
|
|
}
|
|
|
|
free(buf);
|
|
|
|
return total;
|
|
|
|
error_dump_line:
|
|
error_read:
|
|
free(buf);
|
|
|
|
error_malloc:
|
|
error_fstat:
|
|
return -1;
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
int fd;
|
|
|
|
if (argc == 1) {
|
|
fd = fileno(stdin);
|
|
} else if (argc == 2) {
|
|
if ((fd = open(argv[1], O_RDONLY)) < 0) {
|
|
goto error_open;
|
|
}
|
|
} else {
|
|
usage(argc, argv, "Too many arguments provided");
|
|
}
|
|
|
|
if (dump_fd(fd) < 0) {
|
|
fprintf(stderr, "%s: %s: %s\n",
|
|
argv[0],
|
|
(argc == 2)? argv[1]: "(stdin)",
|
|
strerror(errno));
|
|
|
|
goto error_dump_fd;
|
|
}
|
|
|
|
if (argc == 2) {
|
|
close(fd);
|
|
}
|
|
|
|
return 0;
|
|
|
|
error_dump_fd:
|
|
if (argc == 2) {
|
|
close(fd);
|
|
}
|
|
|
|
error_open:
|
|
return 1;
|
|
}
|