/* * Tool for decoding compact index values for testing. * Copyright © 2012 Nick Bowler * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #define PROGNAME "decodeindex" static const char *progname = PROGNAME; static const unsigned char sopts[] = "VH"; static const struct option lopts[] = { { "version", 0, NULL, 'V' }, { "help", 0, NULL, 'H' }, { 0 } }; /* * Decode a hexadecimal string into a sequence of bytes. If there are an * odd number of nibbles, treat the first character as the least significant * nibble of the first byte. The result is written to the buffer specified by * buf. At most n bytes are written to the buffer. * * Returns the number of bytes that would be written provided that n was large * enough, or (size_t)-1 if the input is not valid. */ static size_t decode_hex(const char *hex, unsigned char *buf, size_t n) { size_t len, count = 0; char tmp[] = "00"; for (len = 0; hex[len]; len++) { if (!isxdigit(hex[len])) return -1; } if (!len) return 0; switch (len % 2) { while (len > 0) { case 0: tmp[0] = *hex++; len--; case 1: tmp[1] = *hex++; len--; if (count < n) buf[count] = strtoul(tmp, NULL, 16); count++; } } return count; } static void print_usage(FILE *f) { fprintf(f, "Usage: %s [options] index [index ...]\n", progname); } static void print_version(void) { printf("%s (%s) %s\n", PROGNAME, PACKAGE_NAME, PACKAGE_VERSION); puts("Copyright (C) 2012 Nick Bowler."); puts("License GPLv3+: GNU GPL version 3 or later ."); puts("This is free software: you are free to change and redistribute it."); puts("There is NO WARRANTY, to the extent permitted by law."); } static void print_bytes(FILE *f, int indent, void *buf, size_t n) { fprintf(f, "%*s", indent, ""); for (size_t i = 0; i < n; i++) fprintf(f, "%*s%.2hhx", i != 0, "", ((unsigned char *)buf)[i]); putc('\n', f); } static int print_index(const char *hex) { unsigned char buf[32]; long index = 0; size_t n, rc; int ret = -1; n = decode_hex(hex, buf, sizeof buf); if (n == -1) { fprintf(stderr, "%s: invalid hex sequence: %s\n", progname, hex); goto out; } else if (n == 0) { fprintf(stderr, "%s: empty argument\n", progname); goto out; } else if (n > sizeof buf) { fprintf(stderr, "%s: hex sequence too long: %s\n", progname, hex); goto out; } rc = upkg_decode_index(&index, buf, n); if (rc == 0) { fprintf(stderr, "%s: invalid index encoding:\n", progname); print_bytes(stderr, 4, buf, n); goto out; } else if (rc < n) { fprintf(stderr, "%s: trailing bytes in argument:\n", progname); print_bytes(stderr, 4, buf+rc, n-rc); /* Non-fatal */ } ret = 0; out: printf("%ld\n", index); return ret; } int main(int argc, char **argv) { int opt, ret = EXIT_SUCCESS; if (argc > 0) progname = argv[0]; while ((opt = getopt_long(argc, argv, sopts, lopts, NULL)) != -1) { switch (opt) { case 'V': print_version(); return EXIT_SUCCESS; case 'H': print_usage(stdout); return EXIT_SUCCESS; default: print_usage(stderr); return EXIT_FAILURE; } } if (!argv[optind]) { print_usage(stderr); return EXIT_FAILURE; } for (int i = optind; i < argc; i++) { if (print_index(argv[i]) != 0) { ret = EXIT_FAILURE; } } return ret; }