Skip to content

Commit

Permalink
base58check.c: implement hex data input/output + other enhancements
Browse files Browse the repository at this point in the history
  • Loading branch information
whitslack committed Mar 1, 2024
1 parent c7d16e3 commit 963f531
Showing 1 changed file with 66 additions and 14 deletions.
80 changes: 66 additions & 14 deletions base58check.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,58 @@
#include <getopt.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
#include <sysexits.h>
#include <unistd.h>


static void print_usage() {
fprintf(stderr, "usage: %s [-d]\n\n"
fprintf(stderr, "usage: %s [-d] [-h]\n\n"
"Reads data from stdin, encodes it in Base58Check, and writes the encoding to\n"
"stdout. Specify -d to decode instead.\n",
"stdout. Specify -d to decode instead. Specify -h to use hex data input/output.\n",
program_invocation_short_name);
}

static int gethex() {
static const int8_t DECODE['f' + 1 - '0'] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, 10, 11, 12, 13, 14, 15
};
int hi, lo;
if ((hi = getchar()) < 0)
return hi;
if ((hi -= '0') >= 0 && hi <= 'f' - '0' && (hi = DECODE[hi]) >= 0) {
if ((lo = getchar()) >= 0 && (lo -= '0') >= 0 && lo <= 'f' - '0' && (lo = DECODE[lo]) >= 0)
return hi << 4 | lo;
}
else if (hi == '\n' - '0')
return EOF;
errx(EX_DATAERR, "invalid hex on stdin");
}

static ssize_t fwrite_hex(const unsigned char in[], size_t n_in, FILE *out) {
static const char ENCODE[16] = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
};
for (size_t i = 0; i < n_in; ++i) {
char x[2] = { ENCODE[in[i] >> 4], ENCODE[in[i] & 0xF] };
if (fwrite(x, 1, 2, out) < 2)
return -1;
}
return putc('\n', out) < 0 ? -1 : (ssize_t) n_in;
}

int main(int argc, char *argv[]) {
static const struct option longopts[] = {
{ .name = "decode", .has_arg = no_argument, .val = 'd' },
{ .name = "hex", .has_arg = no_argument, .val = 'h' },
{ .name = "help", .has_arg = no_argument, .val = 1 },
{ .name = "version", .has_arg = no_argument, .val = 2 },
{ }
};
bool decode = false;
for (int opt; (opt = getopt_long(argc, argv, "d", longopts, NULL)) >= 0;) {
bool decode = false, hex = false;
for (int opt; (opt = getopt_long(argc, argv, "dh", longopts, NULL)) >= 0;) {
switch (opt) {
case 1:
print_usage();
Expand All @@ -37,36 +69,56 @@ int main(int argc, char *argv[]) {
case 'd':
decode = true;
break;
case 'h':
hex = true;
break;
default:
print_usage();
return EX_USAGE;
}
}
if (optind != argc)
return print_usage(), EX_USAGE;

unsigned char in[4096];
size_t n_in = 0;

for (size_t r; n_in < sizeof in && (r = fread(in + n_in, 1, sizeof in - n_in, stdin)) > 0; n_in += r);
if (ferror(stdin) || n_in == sizeof in)
return EX_IOERR;
if (decode || hex) {
for (int c;;) {
if (decode ? (c = getchar()) < 0 || c == '\n' : (c = gethex()) < 0) {
if (ferror(stdin))
err(EX_IOERR, "error reading from stdin");
break;
}
if (n_in == sizeof in)
errx(EX_DATAERR, "input is too long");
in[n_in++] = (unsigned char) c;
}
}
else {
n_in = fread(in, 1, sizeof in, stdin);
if (ferror(stdin))
err(EX_IOERR, "error reading from stdin");
if (!feof(stdin) && getchar() >= 0)
errx(EX_DATAERR, "input is too long");
}

unsigned char *out = NULL;
size_t n_out = 0;
if (decode) {
if (n_in && in[n_in - 1] == '\n')
in[--n_in] = '\0';
if (base58check_decode(&out, &n_out, (char *) in, n_in, 0))
errx(EX_DATAERR, "input was not a valid Base58Check encoding");
}
else {
n_out = 1;
if (base58check_encode((char **) &out, &n_out, in, n_in, 0))
return EX_UNAVAILABLE;
errx(EX_SOFTWARE, "internal error");
out[n_out++] = '\n';
}

if (fwrite(out, 1, n_out, stdout) < n_out)
return EX_IOERR;
if (hex && decode ?
fwrite_hex((const unsigned char *) out, n_out, stdout) < (ssize_t) n_out :
fwrite(out, 1, n_out, stdout) < n_out)
err(EX_IOERR, "error writing to stdout");

return EX_OK;
}

0 comments on commit 963f531

Please sign in to comment.