/* * Copyright (c) 2004-2019 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #define DEF_BYTES_PER_LINE 16 static int bytes_per_line = DEF_BYTES_PER_LINE; static const char * version_str = "1.11 20190527"; #define CHARS_PER_HEX_BYTE 3 #define BINARY_START_COL 6 #define MAX_LINE_LENGTH 257 #ifdef SG_LIB_MINGW /* Non Unix OSes distinguish between text and binary files. Set text mode on fd. Does nothing in Unix. Returns negative number on failure. */ int sg_set_text_mode(int fd) { return setmode(fd, O_TEXT); } /* Set binary mode on fd. Does nothing in Unix. Returns negative number on failure. */ int sg_set_binary_mode(int fd) { return setmode(fd, O_BINARY); } #else /* For Unix the following functions are dummies. */ int sg_set_text_mode(int fd) { return fd; /* fd should be >= 0 */ } int sg_set_binary_mode(int fd) { return fd; } #endif /* Returns the number of times 'ch' is found in string 's' given the * string's length. */ static int num_chs_in_str(const char * s, int slen, int ch) { int res = 0; while (--slen >= 0) { if (ch == s[slen]) ++res; } return res; } /* If the number in 'buf' can be decoded or the multiplier is unknown * then -1LL is returned. Accepts a hex prefix (0x or 0X) or a decimal * multiplier suffix (as per GNU's dd (since 2002: SI and IEC 60027-2)). * Main (SI) multipliers supported: K, M, G, T, P. Ignore leading spaces * and tabs; accept comma, hyphen, space, tab and hash as terminator. */ int64_t sg_get_llnum(const char * buf) { int res, len, n; int64_t num, ll; uint64_t unum; char * cp; const char * b; char c = 'c'; char c2 = '\0'; /* keep static checker happy */ char c3 = '\0'; /* keep static checker happy */ char lb[32]; if ((NULL == buf) || ('\0' == buf[0])) return -1LL; len = strlen(buf); n = strspn(buf, " \t"); if (n > 0) { if (n == len) return -1LL; buf += n; len -= n; } /* following hack to keep C++ happy */ cp = strpbrk((char *)buf, " \t,#-"); if (cp) { len = cp - buf; n = (int)sizeof(lb) - 1; len = (len < n) ? len : n; memcpy(lb, buf, len); lb[len] = '\0'; b = lb; } else b = buf; if (('0' == b[0]) && (('x' == b[1]) || ('X' == b[1]))) { res = sscanf(b + 2, "%" SCNx64 , &unum); num = unum; } else if ('H' == toupper((int)b[len - 1])) { res = sscanf(b, "%" SCNx64 , &unum); num = unum; } else res = sscanf(b, "%" SCNd64 "%c%c%c", &num, &c, &c2, &c3); if (res < 1) return -1LL; else if (1 == res) return num; else { if (res > 2) c2 = toupper((int)c2); if (res > 3) c3 = toupper((int)c3); switch (toupper((int)c)) { case 'C': return num; case 'W': return num * 2; case 'B': return num * 512; case 'K': if (2 == res) return num * 1024; if (('B' == c2) || ('D' == c2)) return num * 1000; if (('I' == c2) && (4 == res) && ('B' == c3)) return num * 1024; return -1LL; case 'M': if (2 == res) return num * 1048576; if (('B' == c2) || ('D' == c2)) return num * 1000000; if (('I' == c2) && (4 == res) && ('B' == c3)) return num * 1048576; return -1LL; case 'G': if (2 == res) return num * 1073741824; if (('B' == c2) || ('D' == c2)) return num * 1000000000; if (('I' == c2) && (4 == res) && ('B' == c3)) return num * 1073741824; return -1LL; case 'T': if (2 == res) return num * 1099511627776LL; if (('B' == c2) || ('D' == c2)) return num * 1000000000000LL; if (('I' == c2) && (4 == res) && ('B' == c3)) return num * 1099511627776LL; return -1LL; case 'P': if (2 == res) return num * 1099511627776LL * 1024; if (('B' == c2) || ('D' == c2)) return num * 1000000000000LL * 1000; if (('I' == c2) && (4 == res) && ('B' == c3)) return num * 1099511627776LL * 1024; return -1LL; case 'X': cp = (char *)strchr(b, 'x'); if (NULL == cp) cp = (char *)strchr(b, 'X'); if (cp) { ll = sg_get_llnum(cp + 1); if (-1LL != ll) return num * ll; } return -1LL; default: fprintf(stderr, "unrecognized multiplier\n"); return -1LL; } } } static void dStrHex(const char* str, int len, long start, int noAddr) { const char* p = str; unsigned char c; char buff[MAX_LINE_LENGTH]; long a = start; int bpstart, cpstart; int j, k, line_length, nl, cpos, bpos, midline_space; if (noAddr) { bpstart = 0; cpstart = ((CHARS_PER_HEX_BYTE * bytes_per_line) + 1) + 5; } else { bpstart = BINARY_START_COL; cpstart = BINARY_START_COL + ((CHARS_PER_HEX_BYTE * bytes_per_line) + 1) + 5; } cpos = cpstart; bpos = bpstart; midline_space = ((bytes_per_line + 1) / 2); if (len <= 0) return; line_length = BINARY_START_COL + (bytes_per_line * (1 + CHARS_PER_HEX_BYTE)) + 7; if (line_length >= MAX_LINE_LENGTH) { fprintf(stderr, "bytes_per_line causes maximum line length of %d " "to be exceeded\n", MAX_LINE_LENGTH); return; } memset(buff, ' ', line_length); buff[line_length] = '\0'; if (0 == noAddr) { k = sprintf(buff + 1, "%.2lx", a); buff[k + 1] = ' '; } for(j = 0; j < len; j++) { nl = (0 == (j % bytes_per_line)); if ((j > 0) && nl) { printf("%s\n", buff); bpos = bpstart; cpos = cpstart; a += bytes_per_line; memset(buff,' ', line_length); if (0 == noAddr) { k = sprintf(buff + 1, "%.2lx", a); buff[k + 1] = ' '; } } c = *p++; bpos += (nl && noAddr) ? 0 : CHARS_PER_HEX_BYTE; if ((bytes_per_line > 4) && ((j % bytes_per_line) == midline_space)) bpos++; sprintf(&buff[bpos], "%.2x", (int)(unsigned char)c); buff[bpos + 2] = ' '; if ((c < ' ') || (c >= 0x7f)) c='.'; buff[cpos++] = c; } if (cpos > cpstart) printf("%s\n", buff); } static void dStrHexOnly(const char* str, int len, long start, int noAddr) { const char* p = str; unsigned char c; char buff[MAX_LINE_LENGTH]; long a = start; int bpstart, bpos, nl; int midline_space = ((bytes_per_line + 1) / 2); int j, k, line_length; if (len <= 0) return; bpstart = (noAddr ? 0 : BINARY_START_COL); bpos = bpstart; line_length = (noAddr ? 0 : BINARY_START_COL) + (bytes_per_line * CHARS_PER_HEX_BYTE) + 4; if (line_length >= MAX_LINE_LENGTH) { fprintf(stderr, "bytes_per_line causes maximum line length of %d " "to be exceeded\n", MAX_LINE_LENGTH); return; } memset(buff, ' ', line_length); buff[line_length] = '\0'; if (0 == noAddr) { k = sprintf(buff + 1, "%.2lx", a); buff[k + 1] = ' '; } for(j = 0; j < len; j++) { nl = (0 == (j % bytes_per_line)); if ((j > 0) && nl) { printf("%s\n", buff); bpos = bpstart; a += bytes_per_line; memset(buff,' ', line_length); if (0 == noAddr) { k = sprintf(buff + 1, "%.2lx", a); buff[k + 1] = ' '; } } c = *p++; bpos += (nl && noAddr) ? 0 : CHARS_PER_HEX_BYTE; if ((bytes_per_line > 4) && ((j % bytes_per_line) == midline_space)) bpos++; sprintf(&buff[bpos], "%.2x", (int)(unsigned char)c); buff[bpos + 2] = ' '; } if (bpos > bpstart) printf("%s\n", buff); } static void usage() { fprintf(stderr, "Usage: hxascdmp [-1] [-2] [-b=] [-h] [-H] [-N] " "[-o=] [-q]\n" " [-V] [-?] [+]\n"); fprintf(stderr, " where:\n"); fprintf(stderr, " -1 print first byte in hex, prepend '0x' " "if '-H' given\n"); fprintf(stderr, " -2 like '-1' but print first two bytes\n"); fprintf(stderr, " -b= bytes per line to display " "(def: 16)\n"); fprintf(stderr, " -h print this usage message\n"); fprintf(stderr, " -H print hex only (i.e. no ASCII " "to right)\n"); fprintf(stderr, " -N no address, start in first column\n"); fprintf(stderr, " -o= start decoding at byte . Suffix " "multipliers allowed\n"); fprintf(stderr, " -q quiet: suppress output of header " "info\n"); fprintf(stderr, " -V print version string then exits\n"); fprintf(stderr, " -? print this usage message\n"); fprintf(stderr, " + reads file(s) and outputs each " "as hex ASCII\n"); fprintf(stderr, " if no then reads stdin\n\n"); fprintf(stderr, "Sends hex ASCII dump of stdin/file to stdout\n"); } int main(int argc, const char ** argv) { char buff[8192]; int num = 8192; long start = 0; int64_t offset = 0; int res, k, u, len, n; int inFile = STDIN_FILENO; int doHelp = 0; int doHex = 0; int noAddr = 0; int doVersion = 0; int hasFilename = 0; int quiet = 0; int print1 = 0; int print2 = 0; int ret = 0; const char * cp; for (k = 1; k < argc; k++) { cp = argv[k]; len = strlen(cp); if (0 == strncmp("-b=", cp, 3)) { res = sscanf(cp + 3, "%d", &u); if ((1 != res) || (u < 1)) { fprintf(stderr, "Bad value after '-b=' option\n"); usage(); return 1; } bytes_per_line = u; } else if (0 == strncmp("-o=", cp, 3)) { int64_t off = sg_get_llnum(cp + 3); if (off == -1) { fprintf(stderr, "Bad value after '-o=' option\n"); usage(); return 1; } offset = off; } else if ((len > 1) && ('-' == cp[0]) && ('-' != cp[1])) { res = 0; n = num_chs_in_str(cp + 1, len - 1, '1'); print1 += n; res += n; n = num_chs_in_str(cp + 1, len - 1, '2'); print2 += n; res += n; n = num_chs_in_str(cp + 1, len - 1, 'h'); doHelp += n; res += n; n = num_chs_in_str(cp + 1, len - 1, 'H'); doHex += n; res += n; n = num_chs_in_str(cp + 1, len - 1, 'N'); noAddr += n; res += n; n = num_chs_in_str(cp + 1, len - 1, 'q'); quiet += n; res += n; n = num_chs_in_str(cp + 1, len - 1, 'V'); doVersion += n; res += n; n = num_chs_in_str(cp + 1, len - 1, '?'); doHelp += n; res += n; if (0 == res) { fprintf(stderr, "No option recognized in str: %s\n", cp); usage(); return 1; } } else if (0 == strcmp("-?", argv[k])) ++doHelp; else if (*argv[k] == '-') { fprintf(stderr, "unknown switch: %s\n", argv[k]); usage(); return 1; } else { hasFilename = 1; break; } if (print2) print1 += print2 + print2; } if (doVersion) { printf("%s\n", version_str); return 0; } if (doHelp) { usage(); return 0; } /* Make sure num to fetch is integral multiple of bytes_per_line */ if (0 != (num % bytes_per_line)) num = (num / bytes_per_line) * bytes_per_line; if (hasFilename) { for ( ; k < argc; k++) { inFile = open(argv[k], O_RDONLY); if (inFile < 0) { fprintf(stderr, "Couldn't open file: %s\n", argv[k]); ret = 1; } else { sg_set_binary_mode(inFile); if (offset > 0) { int err; int64_t off_res; off_res = lseek(inFile, offset, SEEK_SET); if (off_res < 0) { err = errno; fprintf(stderr, "failed moving filepos: wanted=%" PRId64 " [0x%" PRIx64 "]\nlseek error: %s\n", offset, offset, strerror(err)); goto fini1; } start = offset; } else start = 0; if (! (doHex || quiet || print1)) printf("ASCII hex dump of file: %s\n", argv[k]); while ((res = read(inFile, buff, num)) > 0) { if (print1) { if (1 == print1) { if (doHex) printf("0x%02x\n", (uint8_t)(buff[0])); else printf("%02x\n", (uint8_t)(buff[0])); } else { uint16_t us; memcpy(&us, buff, 2); if (doHex) printf("0x%04x\n", us); else printf("%04x\n", us); } break; } if (doHex) dStrHexOnly(buff, res, start, noAddr); else dStrHex(buff, res, start, noAddr); start += (long)res; } } fini1: close(inFile); } } else { sg_set_binary_mode(inFile); if (offset > 0) { start = offset; do { /* eat up offset bytes */ if ((res = read(inFile, buff, (num > offset ? offset : num))) > 0) offset -= res; else { fprintf(stderr, "offset read() error: %s\n", strerror(errno)); break; } } while (offset > 0); } while ((res = read(inFile, buff, num)) > 0) { if (doHex) dStrHexOnly(buff, res, start, noAddr); else dStrHex(buff, res, start, noAddr); start += (long)res; } } return ret; }