| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | |
| |
|
| | #include <config.h> |
| |
|
| | #include <stdio.h> |
| | #include <getopt.h> |
| | #include <sys/types.h> |
| | #include <gmp.h> |
| |
|
| | #include "system.h" |
| | #include "assure.h" |
| | #include "c-ctype.h" |
| | #include "fadvise.h" |
| | #include "quote.h" |
| | #include "xstrtol.h" |
| | #include "xdectoint.h" |
| | #include "xbinary-io.h" |
| |
|
| | #if BASE_TYPE == 42 |
| | # define AUTHORS \ |
| | proper_name ("Simon Josefsson"), \ |
| | proper_name ("Assaf Gordon") |
| | #else |
| | # define AUTHORS proper_name ("Simon Josefsson") |
| | #endif |
| |
|
| | #if BASE_TYPE == 32 |
| | # include "base32.h" |
| | # define PROGRAM_NAME "base32" |
| | #elif BASE_TYPE == 64 |
| | # include "base64.h" |
| | # define PROGRAM_NAME "base64" |
| | #elif BASE_TYPE == 42 |
| | # include "base32.h" |
| | # include "base64.h" |
| | # include "assure.h" |
| | # define PROGRAM_NAME "basenc" |
| | #else |
| | # error missing/invalid BASE_TYPE definition |
| | #endif |
| |
|
| |
|
| |
|
| | #if BASE_TYPE == 42 |
| | enum |
| | { |
| | BASE64_OPTION = CHAR_MAX + 1, |
| | BASE64URL_OPTION, |
| | BASE58_OPTION, |
| | BASE32_OPTION, |
| | BASE32HEX_OPTION, |
| | BASE16_OPTION, |
| | BASE2MSBF_OPTION, |
| | BASE2LSBF_OPTION, |
| | Z85_OPTION |
| | }; |
| | #endif |
| |
|
| | static struct option const long_options[] = |
| | { |
| | {"decode", no_argument, 0, 'd'}, |
| | {"wrap", required_argument, 0, 'w'}, |
| | {"ignore-garbage", no_argument, 0, 'i'}, |
| | #if BASE_TYPE == 42 |
| | {"base64", no_argument, 0, BASE64_OPTION}, |
| | {"base64url", no_argument, 0, BASE64URL_OPTION}, |
| | {"base58", no_argument, 0, BASE58_OPTION}, |
| | {"base32", no_argument, 0, BASE32_OPTION}, |
| | {"base32hex", no_argument, 0, BASE32HEX_OPTION}, |
| | {"base16", no_argument, 0, BASE16_OPTION}, |
| | {"base2msbf", no_argument, 0, BASE2MSBF_OPTION}, |
| | {"base2lsbf", no_argument, 0, BASE2LSBF_OPTION}, |
| | {"z85", no_argument, 0, Z85_OPTION}, |
| | #endif |
| | {GETOPT_HELP_OPTION_DECL}, |
| | {GETOPT_VERSION_OPTION_DECL}, |
| | {nullptr, 0, nullptr, 0} |
| | }; |
| |
|
| | void |
| | usage (int status) |
| | { |
| | if (status != EXIT_SUCCESS) |
| | emit_try_help (); |
| | else |
| | { |
| | printf (_("\ |
| | Usage: %s [OPTION]... [FILE]\n\ |
| | "), program_name); |
| |
|
| | #if BASE_TYPE == 42 |
| | fputs (_("\ |
| | basenc encode or decode FILE, or standard input, to standard output.\n\ |
| | "), stdout); |
| | #else |
| | printf (_("\ |
| | Base%d encode or decode FILE, or standard input, to standard output.\n\ |
| | "), BASE_TYPE); |
| | #endif |
| |
|
| | emit_stdin_note (); |
| | emit_mandatory_arg_note (); |
| | #if BASE_TYPE == 42 |
| | fputs (_("\ |
| | --base64 same as 'base64' program (RFC4648 section 4)\n\ |
| | "), stdout); |
| | fputs (_("\ |
| | --base64url file- and url-safe base64 (RFC4648 section 5)\n\ |
| | "), stdout); |
| | fputs (_("\ |
| | --base58 visually unambiguous base58 encoding\n\ |
| | "), stdout); |
| | fputs (_("\ |
| | --base32 same as 'base32' program (RFC4648 section 6)\n\ |
| | "), stdout); |
| | fputs (_("\ |
| | --base32hex extended hex alphabet base32 (RFC4648 section 7)\n\ |
| | "), stdout); |
| | fputs (_("\ |
| | --base16 hex encoding (RFC4648 section 8)\n\ |
| | "), stdout); |
| | fputs (_("\ |
| | --base2msbf bit string with most significant bit (msb) first\n\ |
| | "), stdout); |
| | fputs (_("\ |
| | --base2lsbf bit string with least significant bit (lsb) first\n\ |
| | "), stdout); |
| | #endif |
| | fputs (_("\ |
| | -d, --decode decode data\n\ |
| | -i, --ignore-garbage when decoding, ignore non-alphabet characters\n\ |
| | -w, --wrap=COLS wrap encoded lines after COLS character (default 76).\n\ |
| | Use 0 to disable line wrapping\n\ |
| | "), stdout); |
| | #if BASE_TYPE == 42 |
| | fputs (_("\ |
| | --z85 ascii85-like encoding (ZeroMQ spec:32/Z85);\n\ |
| | when encoding, input length must be a multiple of 4;\n\ |
| | when decoding, input length must be a multiple of 5\n\ |
| | "), stdout); |
| | #endif |
| | fputs (HELP_OPTION_DESCRIPTION, stdout); |
| | fputs (VERSION_OPTION_DESCRIPTION, stdout); |
| | #if BASE_TYPE == 42 |
| | fputs (_("\ |
| | \n\ |
| | When decoding, the input may contain newlines in addition to the bytes of\n\ |
| | the formal alphabet. Use --ignore-garbage to attempt to recover\n\ |
| | from any other non-alphabet bytes in the encoded stream.\n\ |
| | "), stdout); |
| | #else |
| | printf (_("\ |
| | \n\ |
| | The data are encoded as described for the %s alphabet in RFC 4648.\n\ |
| | When decoding, the input may contain newlines in addition to the bytes of\n\ |
| | the formal %s alphabet. Use --ignore-garbage to attempt to recover\n\ |
| | from any other non-alphabet bytes in the encoded stream.\n"), |
| | PROGRAM_NAME, PROGRAM_NAME); |
| | #endif |
| | emit_ancillary_info (PROGRAM_NAME); |
| | } |
| |
|
| | exit (status); |
| | } |
| |
|
| | #if BASE_TYPE != 64 |
| | static int |
| | base32_required_padding (int len) |
| | { |
| | int partial = len % 8; |
| | return partial ? 8 - partial : 0; |
| | } |
| | #endif |
| |
|
| | #if BASE_TYPE != 32 |
| | static int |
| | base64_required_padding (int len) |
| | { |
| | int partial = len % 4; |
| | return partial ? 4 - partial : 0; |
| | } |
| | #endif |
| |
|
| | #if BASE_TYPE == 42 |
| | static int |
| | no_required_padding (MAYBE_UNUSED int len) |
| | { |
| | return 0; |
| | } |
| | #endif |
| |
|
| | #define ENC_BLOCKSIZE (1024 * 3 * 10) |
| |
|
| | #if BASE_TYPE == 32 |
| | # define BASE_LENGTH BASE32_LENGTH |
| | # define REQUIRED_PADDING base32_required_padding |
| | |
| | |
| | # define DEC_BLOCKSIZE (1024 * 5) |
| |
|
| | |
| | static_assert (ENC_BLOCKSIZE % 40 == 0); |
| | static_assert (DEC_BLOCKSIZE % 40 == 0); |
| |
|
| | # define base_encode base32_encode |
| | # define base_decode_context base32_decode_context |
| | # define base_decode_ctx_init base32_decode_ctx_init |
| | # define base_decode_ctx base32_decode_ctx |
| | # define base_decode_ctx_finalize decode_ctx_finalize |
| | # define isubase isubase32 |
| | #elif BASE_TYPE == 64 |
| | # define BASE_LENGTH BASE64_LENGTH |
| | # define REQUIRED_PADDING base64_required_padding |
| | |
| | |
| | # define DEC_BLOCKSIZE (1024 * 3) |
| |
|
| | |
| | static_assert (ENC_BLOCKSIZE % 12 == 0); |
| | static_assert (DEC_BLOCKSIZE % 12 == 0); |
| |
|
| | # define base_encode base64_encode |
| | # define base_decode_context base64_decode_context |
| | # define base_decode_ctx_init base64_decode_ctx_init |
| | # define base_decode_ctx base64_decode_ctx |
| | # define base_decode_ctx_finalize decode_ctx_finalize |
| | # define isubase isubase64 |
| | #elif BASE_TYPE == 42 |
| |
|
| |
|
| | # define BASE_LENGTH base_length |
| | # define REQUIRED_PADDING required_padding |
| |
|
| | |
| | |
| | # define DEC_BLOCKSIZE (4200) |
| | static_assert (DEC_BLOCKSIZE % 40 == 0); |
| | static_assert (DEC_BLOCKSIZE % 12 == 0); |
| |
|
| | static idx_t (*base_length) (idx_t len); |
| | static int (*required_padding) (int i); |
| | static bool (*isubase) (unsigned char ch); |
| | static void (*base_encode) (char const *restrict in, idx_t inlen, |
| | char *restrict out, idx_t outlen); |
| |
|
| | struct base16_decode_context |
| | { |
| | |
| | signed char nibble; |
| | }; |
| |
|
| | struct z85_decode_context |
| | { |
| | int i; |
| | unsigned char octets[5]; |
| | }; |
| |
|
| | struct base58_context |
| | { |
| | unsigned char *buf; |
| | idx_t size; |
| | idx_t capacity; |
| | }; |
| |
|
| | struct base2_decode_context |
| | { |
| | unsigned char octet; |
| | int bit_pos; |
| | }; |
| |
|
| | struct base_decode_context |
| | { |
| | union { |
| | struct base64_decode_context base64; |
| | struct base32_decode_context base32; |
| | struct base16_decode_context base16; |
| | struct base2_decode_context base2; |
| | struct z85_decode_context z85; |
| | struct base58_context base58; |
| | } ctx; |
| | char *inbuf; |
| | idx_t bufsize; |
| | }; |
| | static void (*base_decode_ctx_init) (struct base_decode_context *ctx); |
| | static bool (*base_decode_ctx) (struct base_decode_context *ctx, |
| | char const *restrict in, idx_t inlen, |
| | char *restrict out, idx_t *outlen); |
| | static bool (*base_decode_ctx_finalize) (struct base_decode_context *ctx, |
| | char *restrict *out, idx_t *outlen); |
| |
|
| | struct base_encode_context |
| | { |
| | union { |
| | struct base58_context base58; |
| | } ctx; |
| | }; |
| |
|
| | static void (*base_encode_ctx_init) (struct base_encode_context *ctx); |
| | static bool (*base_encode_ctx) (struct base_encode_context *ctx, |
| | char const *restrict in, idx_t inlen, |
| | char *restrict out, idx_t *outlen); |
| | static bool (*base_encode_ctx_finalize) (struct base_encode_context *ctx, |
| | char *restrict *out, idx_t *outlen); |
| |
|
| | static bool |
| | no_padding (MAYBE_UNUSED struct base_decode_context *ctx) |
| | { |
| | return false; |
| | } |
| |
|
| | static int |
| | no_pending_length (MAYBE_UNUSED struct base_decode_context *ctx) |
| | { |
| | return 0; |
| | } |
| | #endif |
| |
|
| | #if BASE_TYPE == 42 |
| | static bool (*has_padding) (struct base_decode_context *ctx); |
| | static int (*get_pending_length) (struct base_decode_context *ctx); |
| |
|
| | static bool |
| | base64_ctx_has_padding (struct base_decode_context *ctx) |
| | { |
| | return ctx->ctx.base64.i && ctx->ctx.base64.buf[ctx->ctx.base64.i - 1] == '='; |
| | } |
| |
|
| | static bool |
| | base32_ctx_has_padding (struct base_decode_context *ctx) |
| | { |
| | return ctx->ctx.base32.i && ctx->ctx.base32.buf[ctx->ctx.base32.i - 1] == '='; |
| | } |
| |
|
| | static int |
| | base64_ctx_get_pending_length (struct base_decode_context *ctx) |
| | { |
| | return ctx->ctx.base64.i; |
| | } |
| |
|
| | static int |
| | base32_ctx_get_pending_length (struct base_decode_context *ctx) |
| | { |
| | return ctx->ctx.base32.i; |
| | } |
| |
|
| | static int |
| | base16_ctx_get_pending_length (MAYBE_UNUSED struct base_decode_context *ctx) |
| | { |
| | return 1; |
| | } |
| |
|
| | static int |
| | z85_ctx_get_pending_length (struct base_decode_context *ctx) |
| | { |
| | return ctx->ctx.z85.i; |
| | } |
| |
|
| | static int |
| | base2_ctx_get_pending_length (struct base_decode_context *ctx) |
| | { |
| | return ctx->ctx.base2.bit_pos; |
| | } |
| | #else |
| | static bool |
| | has_padding (struct base_decode_context *ctx) |
| | { |
| | return ctx->i && ctx->buf[ctx->i - 1] == '='; |
| | } |
| |
|
| | static int |
| | get_pending_length (struct base_decode_context *ctx) |
| | { |
| | return ctx->i; |
| | } |
| | #endif |
| |
|
| |
|
| | |
| | |
| |
|
| | static bool |
| | decode_ctx_finalize (struct base_decode_context *ctx, |
| | char *restrict *out, idx_t *outlen) |
| | { |
| | if (get_pending_length (ctx) == 0) |
| | { |
| | *outlen = 0; |
| | return true; |
| | } |
| |
|
| | |
| | char padbuf[8] ATTRIBUTE_NONSTRING = "========"; |
| | idx_t pending_len = get_pending_length (ctx); |
| | idx_t auto_padding = REQUIRED_PADDING (pending_len); |
| | idx_t n = *outlen; |
| | bool result; |
| |
|
| | if (auto_padding && ! has_padding (ctx)) |
| | { |
| | affirm (auto_padding <= sizeof (padbuf)); |
| | result = base_decode_ctx (ctx, padbuf, auto_padding, *out, &n); |
| | } |
| | else |
| | { |
| | result = base_decode_ctx (ctx, "", 0, *out, &n); |
| | } |
| |
|
| | *outlen = n; |
| | return result; |
| | } |
| |
|
| | #if BASE_TYPE == 42 |
| |
|
| | static idx_t |
| | base64_length_wrapper (idx_t len) |
| | { |
| | return BASE64_LENGTH (len); |
| | } |
| |
|
| | static void |
| | base64_decode_ctx_init_wrapper (struct base_decode_context *ctx) |
| | { |
| | base64_decode_ctx_init (&ctx->ctx.base64); |
| | } |
| |
|
| | static bool |
| | base64_decode_ctx_wrapper (struct base_decode_context *ctx, |
| | char const *restrict in, idx_t inlen, |
| | char *restrict out, idx_t *outlen) |
| | { |
| | return base64_decode_ctx (&ctx->ctx.base64, in, inlen, out, outlen); |
| | } |
| |
|
| | static void |
| | init_inbuf (struct base_decode_context *ctx) |
| | { |
| | ctx->bufsize = DEC_BLOCKSIZE; |
| | ctx->inbuf = xcharalloc (ctx->bufsize); |
| | } |
| |
|
| | static void |
| | prepare_inbuf (struct base_decode_context *ctx, idx_t inlen) |
| | { |
| | if (ctx->bufsize < inlen) |
| | ctx->inbuf = xpalloc (ctx->inbuf, &ctx->bufsize, |
| | inlen - ctx->bufsize, -1, sizeof *ctx->inbuf); |
| | } |
| |
|
| |
|
| | static void |
| | base64url_encode (char const *restrict in, idx_t inlen, |
| | char *restrict out, idx_t outlen) |
| | { |
| | base64_encode (in, inlen, out, outlen); |
| | |
| | char *p = out; |
| | while (outlen--) |
| | { |
| | if (*p == '+') |
| | *p = '-'; |
| | else if (*p == '/') |
| | *p = '_'; |
| | ++p; |
| | } |
| | } |
| |
|
| | static bool |
| | isubase64url (unsigned char ch) |
| | { |
| | return (ch == '-' || ch == '_' |
| | || (ch != '+' && ch != '/' && isubase64 (ch))); |
| | } |
| |
|
| | static void |
| | base64url_decode_ctx_init_wrapper (struct base_decode_context *ctx) |
| | { |
| | base64_decode_ctx_init (&ctx->ctx.base64); |
| | init_inbuf (ctx); |
| | } |
| |
|
| |
|
| | static bool |
| | base64url_decode_ctx_wrapper (struct base_decode_context *ctx, |
| | char const *restrict in, idx_t inlen, |
| | char *restrict out, idx_t *outlen) |
| | { |
| | prepare_inbuf (ctx, inlen); |
| | memcpy (ctx->inbuf, in, inlen); |
| |
|
| | |
| | idx_t i = inlen; |
| | char *p = ctx->inbuf; |
| | while (i--) |
| | { |
| | if (*p == '+' || *p == '/') |
| | { |
| | *outlen = 0; |
| | return false; |
| | } |
| | else if (*p == '-') |
| | *p = '+'; |
| | else if (*p == '_') |
| | *p = '/'; |
| | ++p; |
| | } |
| |
|
| | return base64_decode_ctx (&ctx->ctx.base64, ctx->inbuf, inlen, |
| | out, outlen); |
| | } |
| |
|
| |
|
| |
|
| | static idx_t |
| | base32_length_wrapper (idx_t len) |
| | { |
| | return BASE32_LENGTH (len); |
| | } |
| |
|
| | static void |
| | base32_decode_ctx_init_wrapper (struct base_decode_context *ctx) |
| | { |
| | base32_decode_ctx_init (&ctx->ctx.base32); |
| | } |
| |
|
| | static bool |
| | base32_decode_ctx_wrapper (struct base_decode_context *ctx, |
| | char const *restrict in, idx_t inlen, |
| | char *restrict out, idx_t *outlen) |
| | { |
| | return base32_decode_ctx (&ctx->ctx.base32, in, inlen, out, outlen); |
| | } |
| |
|
| | |
| | |
| | |
| | static const char base32_norm_to_hex[32 + 9] = { |
| | |
| | 'Q', 'R', 'S', 'T', 'U', 'V', |
| |
|
| | 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, |
| |
|
| | |
| | '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', |
| | }; |
| |
|
| | |
| | |
| | |
| | static const char base32_hex_to_norm[32 + 9] = { |
| | |
| | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', |
| |
|
| | 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, |
| |
|
| | |
| | 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', |
| |
|
| | |
| | 'U', 'V', 'W', 'X', 'Y', 'Z', '2', '3', '4', '5', |
| |
|
| | |
| | '6', '7' |
| | }; |
| |
|
| |
|
| | inline static bool |
| | isubase32hex (unsigned char ch) |
| | { |
| | return ('0' <= ch && ch <= '9') || ('A' <= ch && ch <= 'V'); |
| | } |
| |
|
| |
|
| | static void |
| | base32hex_encode (char const *restrict in, idx_t inlen, |
| | char *restrict out, idx_t outlen) |
| | { |
| | base32_encode (in, inlen, out, outlen); |
| |
|
| | for (char *p = out; outlen--; p++) |
| | { |
| | affirm (0x32 <= *p && *p <= 0x5a); |
| | *p = base32_norm_to_hex[*p - 0x32]; |
| | } |
| | } |
| |
|
| |
|
| | static void |
| | base32hex_decode_ctx_init_wrapper (struct base_decode_context *ctx) |
| | { |
| | base32_decode_ctx_init (&ctx->ctx.base32); |
| | init_inbuf (ctx); |
| | } |
| |
|
| |
|
| | static bool |
| | base32hex_decode_ctx_wrapper (struct base_decode_context *ctx, |
| | char const *restrict in, idx_t inlen, |
| | char *restrict out, idx_t *outlen) |
| | { |
| | prepare_inbuf (ctx, inlen); |
| |
|
| | idx_t i = inlen; |
| | char *p = ctx->inbuf; |
| | while (i--) |
| | { |
| | if (isubase32hex (*in)) |
| | *p = base32_hex_to_norm[*in - 0x30]; |
| | else |
| | *p = *in; |
| | ++p; |
| | ++in; |
| | } |
| |
|
| | return base32_decode_ctx (&ctx->ctx.base32, ctx->inbuf, inlen, |
| | out, outlen); |
| | } |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | # define B16(_) \ |
| | ((_) == '0' ? 0 \ |
| | : (_) == '1' ? 1 \ |
| | : (_) == '2' ? 2 \ |
| | : (_) == '3' ? 3 \ |
| | : (_) == '4' ? 4 \ |
| | : (_) == '5' ? 5 \ |
| | : (_) == '6' ? 6 \ |
| | : (_) == '7' ? 7 \ |
| | : (_) == '8' ? 8 \ |
| | : (_) == '9' ? 9 \ |
| | : (_) == 'A' || (_) == 'a' ? 10 \ |
| | : (_) == 'B' || (_) == 'b' ? 11 \ |
| | : (_) == 'C' || (_) == 'c' ? 12 \ |
| | : (_) == 'D' || (_) == 'd' ? 13 \ |
| | : (_) == 'E' || (_) == 'e' ? 14 \ |
| | : (_) == 'F' || (_) == 'f' ? 15 \ |
| | : -1) |
| |
|
| | static signed char const base16_to_int[256] = { |
| | B16 (0), B16 (1), B16 (2), B16 (3), |
| | B16 (4), B16 (5), B16 (6), B16 (7), |
| | B16 (8), B16 (9), B16 (10), B16 (11), |
| | B16 (12), B16 (13), B16 (14), B16 (15), |
| | B16 (16), B16 (17), B16 (18), B16 (19), |
| | B16 (20), B16 (21), B16 (22), B16 (23), |
| | B16 (24), B16 (25), B16 (26), B16 (27), |
| | B16 (28), B16 (29), B16 (30), B16 (31), |
| | B16 (32), B16 (33), B16 (34), B16 (35), |
| | B16 (36), B16 (37), B16 (38), B16 (39), |
| | B16 (40), B16 (41), B16 (42), B16 (43), |
| | B16 (44), B16 (45), B16 (46), B16 (47), |
| | B16 (48), B16 (49), B16 (50), B16 (51), |
| | B16 (52), B16 (53), B16 (54), B16 (55), |
| | B16 (56), B16 (57), B16 (58), B16 (59), |
| | B16 (60), B16 (61), B16 (62), B16 (63), |
| | B16 (32), B16 (65), B16 (66), B16 (67), |
| | B16 (68), B16 (69), B16 (70), B16 (71), |
| | B16 (72), B16 (73), B16 (74), B16 (75), |
| | B16 (76), B16 (77), B16 (78), B16 (79), |
| | B16 (80), B16 (81), B16 (82), B16 (83), |
| | B16 (84), B16 (85), B16 (86), B16 (87), |
| | B16 (88), B16 (89), B16 (90), B16 (91), |
| | B16 (92), B16 (93), B16 (94), B16 (95), |
| | B16 (96), B16 (97), B16 (98), B16 (99), |
| | B16 (100), B16 (101), B16 (102), B16 (103), |
| | B16 (104), B16 (105), B16 (106), B16 (107), |
| | B16 (108), B16 (109), B16 (110), B16 (111), |
| | B16 (112), B16 (113), B16 (114), B16 (115), |
| | B16 (116), B16 (117), B16 (118), B16 (119), |
| | B16 (120), B16 (121), B16 (122), B16 (123), |
| | B16 (124), B16 (125), B16 (126), B16 (127), |
| | B16 (128), B16 (129), B16 (130), B16 (131), |
| | B16 (132), B16 (133), B16 (134), B16 (135), |
| | B16 (136), B16 (137), B16 (138), B16 (139), |
| | B16 (140), B16 (141), B16 (142), B16 (143), |
| | B16 (144), B16 (145), B16 (146), B16 (147), |
| | B16 (148), B16 (149), B16 (150), B16 (151), |
| | B16 (152), B16 (153), B16 (154), B16 (155), |
| | B16 (156), B16 (157), B16 (158), B16 (159), |
| | B16 (160), B16 (161), B16 (162), B16 (163), |
| | B16 (132), B16 (165), B16 (166), B16 (167), |
| | B16 (168), B16 (169), B16 (170), B16 (171), |
| | B16 (172), B16 (173), B16 (174), B16 (175), |
| | B16 (176), B16 (177), B16 (178), B16 (179), |
| | B16 (180), B16 (181), B16 (182), B16 (183), |
| | B16 (184), B16 (185), B16 (186), B16 (187), |
| | B16 (188), B16 (189), B16 (190), B16 (191), |
| | B16 (192), B16 (193), B16 (194), B16 (195), |
| | B16 (196), B16 (197), B16 (198), B16 (199), |
| | B16 (200), B16 (201), B16 (202), B16 (203), |
| | B16 (204), B16 (205), B16 (206), B16 (207), |
| | B16 (208), B16 (209), B16 (210), B16 (211), |
| | B16 (212), B16 (213), B16 (214), B16 (215), |
| | B16 (216), B16 (217), B16 (218), B16 (219), |
| | B16 (220), B16 (221), B16 (222), B16 (223), |
| | B16 (224), B16 (225), B16 (226), B16 (227), |
| | B16 (228), B16 (229), B16 (230), B16 (231), |
| | B16 (232), B16 (233), B16 (234), B16 (235), |
| | B16 (236), B16 (237), B16 (238), B16 (239), |
| | B16 (240), B16 (241), B16 (242), B16 (243), |
| | B16 (244), B16 (245), B16 (246), B16 (247), |
| | B16 (248), B16 (249), B16 (250), B16 (251), |
| | B16 (252), B16 (253), B16 (254), B16 (255) |
| | }; |
| |
|
| | static bool |
| | isubase16 (unsigned char ch) |
| | { |
| | return ch < sizeof base16_to_int && 0 <= base16_to_int[ch]; |
| | } |
| |
|
| | static idx_t |
| | base16_length (idx_t len) |
| | { |
| | return len * 2; |
| | } |
| |
|
| |
|
| | static void |
| | base16_encode (char const *restrict in, idx_t inlen, |
| | char *restrict out, idx_t outlen) |
| | { |
| | static const char base16[16] ATTRIBUTE_NONSTRING = "0123456789ABCDEF"; |
| |
|
| | while (inlen && outlen) |
| | { |
| | unsigned char c = *in; |
| | *out++ = base16[c >> 4]; |
| | *out++ = base16[c & 0x0F]; |
| | ++in; |
| | inlen--; |
| | outlen -= 2; |
| | } |
| | } |
| |
|
| |
|
| | static void |
| | base16_decode_ctx_init (struct base_decode_context *ctx) |
| | { |
| | init_inbuf (ctx); |
| | ctx->ctx.base16.nibble = -1; |
| | } |
| |
|
| |
|
| | static bool |
| | base16_decode_ctx (struct base_decode_context *ctx, |
| | char const *restrict in, idx_t inlen, |
| | char *restrict out, idx_t *outlen) |
| | { |
| | bool ignore_lines = true; |
| | char *out0 = out; |
| | signed char nibble = ctx->ctx.base16.nibble; |
| |
|
| | |
| | |
| | |
| | if (inlen == 0) |
| | { |
| | *outlen = 0; |
| | return nibble < 0; |
| | } |
| |
|
| | while (inlen--) |
| | { |
| | unsigned char c = *in++; |
| | if (ignore_lines && c == '\n') |
| | continue; |
| |
|
| | if (sizeof base16_to_int <= c || base16_to_int[c] < 0) |
| | { |
| | *outlen = out - out0; |
| | return false; |
| | } |
| |
|
| | if (nibble < 0) |
| | nibble = base16_to_int[c]; |
| | else |
| | { |
| | |
| | *out++ = (nibble << 4) + base16_to_int[c]; |
| | nibble = -1; |
| | } |
| | } |
| |
|
| | ctx->ctx.base16.nibble = nibble; |
| | *outlen = out - out0; |
| | return true; |
| | } |
| |
|
| |
|
| |
|
| | ATTRIBUTE_PURE |
| | static idx_t |
| | z85_length (idx_t len) |
| | { |
| | |
| | idx_t z85_len = (len * 5) / 4; |
| | affirm (0 <= z85_len); |
| | return z85_len; |
| | } |
| |
|
| | static bool |
| | isuz85 (unsigned char ch) |
| | { |
| | return c_isalnum (ch) || strchr (".-:+=^!/*?&<>()[]{}@%$#", ch) != nullptr; |
| | } |
| |
|
| | static char const z85_encoding[85] ATTRIBUTE_NONSTRING = |
| | "0123456789" |
| | "abcdefghijklmnopqrstuvwxyz" |
| | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
| | ".-:+=^!/*?&<>()[]{}@%$#"; |
| |
|
| | static void |
| | z85_encode (char const *restrict in, idx_t inlen, |
| | char *restrict out, idx_t outlen) |
| | { |
| | int i = 0; |
| | unsigned char quad[4]; |
| | idx_t outidx = 0; |
| |
|
| | while (true) |
| | { |
| | if (inlen == 0) |
| | { |
| | |
| | if (i == 0) |
| | return; |
| |
|
| | |
| | error (EXIT_FAILURE, 0, |
| | _("invalid input (length must be multiple of 4 characters)")); |
| | } |
| | else |
| | { |
| | quad[i++] = *in++; |
| | --inlen; |
| | } |
| |
|
| | |
| | if (i == 4) |
| | { |
| | int_fast64_t val = quad[0]; |
| | val = (val << 24) + (quad[1] << 16) + (quad[2] << 8) + quad[3]; |
| |
|
| | for (int j = 4; j >= 0; --j) |
| | { |
| | int c = val % 85; |
| | val /= 85; |
| |
|
| | |
| | |
| | |
| | |
| | if (outidx + j < outlen) |
| | out[j] = z85_encoding[c]; |
| | } |
| | out += 5; |
| | outidx += 5; |
| | i = 0; |
| | } |
| | } |
| | } |
| |
|
| | static void |
| | z85_decode_ctx_init (struct base_decode_context *ctx) |
| | { |
| | init_inbuf (ctx); |
| | ctx->ctx.z85.i = 0; |
| | } |
| |
|
| |
|
| | # define Z85_LO_CTX_TO_32BIT_VAL(ctx) \ |
| | (((ctx)->ctx.z85.octets[1] * 85 * 85 * 85) + \ |
| | ((ctx)->ctx.z85.octets[2] * 85 * 85) + \ |
| | ((ctx)->ctx.z85.octets[3] * 85) + \ |
| | ((ctx)->ctx.z85.octets[4])) |
| |
|
| |
|
| | # define Z85_HI_CTX_TO_32BIT_VAL(ctx) \ |
| | ((int_fast64_t) (ctx)->ctx.z85.octets[0] * 85 * 85 * 85 * 85 ) |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | static signed char const z85_decoding[93] = { |
| | 68, -1, 84, 83, 82, 72, -1, |
| | 75, 76, 70, 65, -1, 63, 62, 69, |
| | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, |
| | 64, -1, 73, 66, 74, 71, 81, |
| | 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, |
| | 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, |
| | 56, 57, 58, 59, 60, 61, |
| | 77, -1, 78, 67, -1, -1, |
| | 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, |
| | 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, |
| | 30, 31, 32, 33, 34, 35, |
| | 79, -1, 80 |
| | }; |
| |
|
| | static bool |
| | z85_decode_ctx (struct base_decode_context *ctx, |
| | char const *restrict in, idx_t inlen, |
| | char *restrict out, idx_t *outlen) |
| | { |
| | bool ignore_lines = true; |
| |
|
| | *outlen = 0; |
| |
|
| | |
| | |
| | |
| | if (inlen == 0) |
| | { |
| | if (ctx->ctx.z85.i > 0) |
| | { |
| | |
| | |
| | return false; |
| | } |
| | return true; |
| | } |
| |
|
| | while (inlen--) |
| | { |
| | if (ignore_lines && *in == '\n') |
| | { |
| | ++in; |
| | continue; |
| | } |
| |
|
| | |
| | unsigned char c = *in; |
| |
|
| | if (c >= 33 && c <= 125) |
| | { |
| | signed char ch = z85_decoding[c - 33]; |
| | if (ch < 0) |
| | return false; |
| | c = ch; |
| | } |
| | else |
| | return false; |
| |
|
| | ++in; |
| |
|
| | ctx->ctx.z85.octets[ctx->ctx.z85.i++] = c; |
| | if (ctx->ctx.z85.i == 5) |
| | { |
| | |
| | int_fast64_t val = Z85_LO_CTX_TO_32BIT_VAL (ctx); |
| |
|
| | |
| | |
| |
|
| | val += Z85_HI_CTX_TO_32BIT_VAL (ctx); |
| | if ((val >> 24) & ~0xFF) |
| | return false; |
| |
|
| | *out++ = val >> 24; |
| | *out++ = (val >> 16) & 0xFF; |
| | *out++ = (val >> 8) & 0xFF; |
| | *out++ = val & 0xFF; |
| |
|
| | *outlen += 4; |
| |
|
| | ctx->ctx.z85.i = 0; |
| | } |
| | } |
| | return true; |
| | } |
| |
|
| |
|
| | inline static bool |
| | isubase2 (unsigned char ch) |
| | { |
| | return ch == '0' || ch == '1'; |
| | } |
| |
|
| | static idx_t |
| | base2_length (idx_t len) |
| | { |
| | return len * 8; |
| | } |
| |
|
| |
|
| | inline static void |
| | base2msbf_encode (char const *restrict in, idx_t inlen, |
| | char *restrict out, idx_t outlen) |
| | { |
| | while (inlen && outlen) |
| | { |
| | unsigned char c = *in; |
| | for (int i = 0; i < 8; i++) |
| | { |
| | *out++ = c & 0x80 ? '1' : '0'; |
| | c <<= 1; |
| | } |
| | inlen--; |
| | outlen -= 8; |
| | ++in; |
| | } |
| | } |
| |
|
| | inline static void |
| | base2lsbf_encode (char const *restrict in, idx_t inlen, |
| | char *restrict out, idx_t outlen) |
| | { |
| | while (inlen && outlen) |
| | { |
| | unsigned char c = *in; |
| | for (int i = 0; i < 8; i++) |
| | { |
| | *out++ = c & 0x01 ? '1' : '0'; |
| | c >>= 1; |
| | } |
| | inlen--; |
| | outlen -= 8; |
| | ++in; |
| | } |
| | } |
| |
|
| |
|
| | static void |
| | base2_decode_ctx_init (struct base_decode_context *ctx) |
| | { |
| | init_inbuf (ctx); |
| | ctx->ctx.base2.octet = 0; |
| | ctx->ctx.base2.bit_pos = 0; |
| | } |
| |
|
| |
|
| | static bool |
| | base2lsbf_decode_ctx (struct base_decode_context *ctx, |
| | char const *restrict in, idx_t inlen, |
| | char *restrict out, idx_t *outlen) |
| | { |
| | bool ignore_lines = true; |
| |
|
| | *outlen = 0; |
| |
|
| | |
| | |
| | |
| | if (inlen == 0) |
| | return ctx->ctx.base2.bit_pos == 0; |
| |
|
| | while (inlen--) |
| | { |
| | if (ignore_lines && *in == '\n') |
| | { |
| | ++in; |
| | continue; |
| | } |
| |
|
| | if (!isubase2 (*in)) |
| | return false; |
| |
|
| | bool bit = (*in == '1'); |
| | ctx->ctx.base2.octet |= bit << ctx->ctx.base2.bit_pos; |
| | ++ctx->ctx.base2.bit_pos; |
| |
|
| | if (ctx->ctx.base2.bit_pos == 8) |
| | { |
| | *out++ = ctx->ctx.base2.octet; |
| | ctx->ctx.base2.octet = 0; |
| | ++*outlen; |
| | ctx->ctx.base2.bit_pos = 0; |
| | } |
| |
|
| | ++in; |
| | } |
| |
|
| | return true; |
| | } |
| |
|
| | static bool |
| | base2msbf_decode_ctx (struct base_decode_context *ctx, |
| | char const *restrict in, idx_t inlen, |
| | char *restrict out, idx_t *outlen) |
| | { |
| | bool ignore_lines = true; |
| |
|
| | *outlen = 0; |
| |
|
| | |
| | |
| | |
| | if (inlen == 0) |
| | return ctx->ctx.base2.bit_pos == 0; |
| |
|
| | while (inlen--) |
| | { |
| | if (ignore_lines && *in == '\n') |
| | { |
| | ++in; |
| | continue; |
| | } |
| |
|
| | if (!isubase2 (*in)) |
| | return false; |
| |
|
| | bool bit = (*in == '1'); |
| | if (ctx->ctx.base2.bit_pos == 0) |
| | ctx->ctx.base2.bit_pos = 8; |
| | --ctx->ctx.base2.bit_pos; |
| | ctx->ctx.base2.octet |= bit << ctx->ctx.base2.bit_pos; |
| |
|
| | if (ctx->ctx.base2.bit_pos == 0) |
| | { |
| | *out++ = ctx->ctx.base2.octet; |
| | ctx->ctx.base2.octet = 0; |
| | ++*outlen; |
| | } |
| |
|
| | ++in; |
| | } |
| |
|
| | return true; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | static signed char const gmp_to_base58[256] = { |
| | -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, -1, -1, -1, -1, -1, -1, |
| | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| | '1','2','3','4','5','6','7','8','9','A',-1, -1, -1, -1, -1, -1, |
| | -1, 'B','C','D','E','F','G','H','J','K','L','M','N','P','Q','R', |
| | 'S','T','U','V','W','X','Y','Z','a','b','c',-1, -1, -1, -1, -1, |
| | -1, 'd','e','f','g','h','i','j','k','m','n','o','p','q','r','s', |
| | 't','u','v','w','x','y','z',-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, -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, -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, -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, -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, -1, -1, -1, -1, -1, -1, -1 |
| | }; |
| |
|
| | static signed char const base58_to_gmp[256] = { |
| | -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, -1, -1, -1, -1, -1, -1, |
| | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
| | -1, '0','1','2','3','4','5','6','7','8',-1, -1, -1, -1, -1, -1, |
| | -1, '9','A','B','C','D','E','F','G', -1,'H','I','J','K','L',-1, |
| | 'M','N','O','P','Q','R','S','T','U','V','W',-1, -1, -1, -1, -1, |
| | -1, 'X','Y','Z','a','b','c','d','e','f','g','h',-1, 'i','j','k', |
| | 'l','m','n','o','p','q','r','s','t','u','v',-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, -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, -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, -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, -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, -1, -1, -1 |
| | }; |
| |
|
| | static bool |
| | isubase58 (unsigned char ch) |
| | { |
| | return ch < sizeof base58_to_gmp && 0 <= base58_to_gmp[ch]; |
| | } |
| |
|
| |
|
| | ATTRIBUTE_PURE |
| | static idx_t |
| | base58_length (idx_t len) |
| | { |
| | |
| | |
| | |
| | |
| | idx_t base58_len = ((len + 99) / 100) * 138 + 1; |
| | affirm (0 < base58_len); |
| | return base58_len; |
| | } |
| |
|
| |
|
| | static void |
| | base58_encode_ctx_init (struct base_encode_context *ctx) |
| | { |
| | ctx->ctx.base58.buf = nullptr; |
| | ctx->ctx.base58.size = 0; |
| | ctx->ctx.base58.capacity = 0; |
| | } |
| |
|
| |
|
| | static bool |
| | base58_encode_ctx (struct base_encode_context *ctx, |
| | char const *restrict in, idx_t inlen, |
| | MAYBE_UNUSED char *restrict out, idx_t *outlen) |
| | { |
| | *outlen = 0; |
| |
|
| | if (inlen == 0) |
| | return true; |
| |
|
| | idx_t free_space = ctx->ctx.base58.capacity - ctx->ctx.base58.size; |
| | if (free_space < inlen) |
| | { |
| | ctx->ctx.base58.buf = xpalloc (ctx->ctx.base58.buf, |
| | &ctx->ctx.base58.capacity, |
| | inlen - free_space, |
| | -1, sizeof *ctx->ctx.base58.buf); |
| | } |
| |
|
| | memcpy (ctx->ctx.base58.buf + ctx->ctx.base58.size, in, inlen); |
| | ctx->ctx.base58.size += inlen; |
| |
|
| | return true; |
| | } |
| |
|
| | static void |
| | base58_encode (char const* data, size_t data_len, |
| | char *out, idx_t *outlen) |
| | { |
| | affirm (base_length (data_len) <= *outlen); |
| |
|
| | size_t zeros = 0; |
| | while (zeros < data_len && data[zeros] == 0) |
| | zeros++; |
| |
|
| | memset (out, '1', zeros); |
| | char *p = out + zeros; |
| |
|
| | |
| | mpz_t num; |
| | mpz_init (num); |
| | if (data_len - zeros) |
| | { |
| | mpz_import (num, data_len - zeros, 1, 1, 0, 0, data + zeros); |
| | affirm (mpz_sizeinbase (num, 58) + 1 <= *outlen); |
| | for (p = mpz_get_str (p, 58, num); *p; p++) |
| | *p = gmp_to_base58[to_uchar (*p)]; |
| | } |
| | mpz_clear (num); |
| |
|
| | *outlen = p - out; |
| | } |
| |
|
| |
|
| | static bool |
| | base58_encode_ctx_finalize (struct base_encode_context *ctx, |
| | char *restrict *out, idx_t *outlen) |
| | { |
| | |
| | idx_t max_outlen = base_length (ctx->ctx.base58.size); |
| | if (max_outlen > *outlen) |
| | { |
| | *out = xrealloc (*out, max_outlen); |
| | *outlen = max_outlen; |
| | } |
| |
|
| | base58_encode ((char *)ctx->ctx.base58.buf, ctx->ctx.base58.size, |
| | *out, outlen); |
| |
|
| | free (ctx->ctx.base58.buf); |
| | ctx->ctx.base58.buf = nullptr; |
| |
|
| | return true; |
| | } |
| |
|
| |
|
| | static void |
| | base58_decode_ctx_init (struct base_decode_context *ctx) |
| | { |
| | ctx->ctx.base58.size = 0; |
| | ctx->ctx.base58.capacity = 0; |
| | ctx->ctx.base58.buf = nullptr; |
| | } |
| |
|
| | static bool |
| | base58_decode_ctx (struct base_decode_context *ctx, |
| | char const *restrict in, idx_t inlen, |
| | MAYBE_UNUSED char *restrict out, idx_t *outlen) |
| | { |
| | bool ignore_lines = true; |
| |
|
| | *outlen = 0; |
| |
|
| | if (inlen == 0) |
| | return true; |
| |
|
| | idx_t free_space = ctx->ctx.base58.capacity - ctx->ctx.base58.size; |
| | free_space -= 1; |
| | if (free_space < inlen) |
| | { |
| | ctx->ctx.base58.buf = xpalloc (ctx->ctx.base58.buf, |
| | &ctx->ctx.base58.capacity, |
| | inlen - free_space, |
| | -1, sizeof *ctx->ctx.base58.buf); |
| | } |
| |
|
| | |
| | |
| | |
| | for (idx_t i = 0; i < inlen; i++) |
| | { |
| | unsigned char c = in[i]; |
| |
|
| | if (ignore_lines && c == '\n') |
| | continue; |
| |
|
| | if (!isubase58 (c)) |
| | return false; |
| |
|
| | ctx->ctx.base58.buf[ctx->ctx.base58.size++] = base58_to_gmp[to_uchar (c)]; |
| | } |
| |
|
| | return true; |
| | } |
| |
|
| |
|
| | static bool |
| | base58_decode (char const *data, size_t data_len, |
| | char *restrict out, idx_t *outlen) |
| | { |
| | affirm (data_len <= *outlen); |
| |
|
| | size_t ones = 0; |
| | while (ones < data_len && data[ones] == base58_to_gmp['1']) |
| | ones++; |
| |
|
| | memset (out, 0, ones); |
| |
|
| | |
| | mpz_t num; |
| | mpz_init (num); |
| |
|
| | if ((data_len - ones) && mpz_set_str (num, data + ones, 58) != 0) |
| | { |
| | mpz_clear (num); |
| | *outlen = 0; |
| | return false; |
| | } |
| |
|
| | size_t exported_size = 0; |
| | if (data_len - ones) |
| | { |
| | size_t binary_size = (mpz_sizeinbase (num, 2) + 7) / 8; |
| | affirm (*outlen - ones >= binary_size); |
| | mpz_export (out + ones, &exported_size, 1, 1, 0, 0, num); |
| | } |
| |
|
| | mpz_clear (num); |
| | *outlen = ones + exported_size; |
| | return true; |
| | } |
| |
|
| |
|
| | static bool |
| | base58_decode_ctx_finalize (struct base_decode_context *ctx, |
| | char *restrict *out, idx_t *outlen) |
| | { |
| | |
| | |
| | idx_t max_outlen = ctx->ctx.base58.size; |
| | if (max_outlen > *outlen) |
| | { |
| | *out = xrealloc (*out, max_outlen); |
| | *outlen = max_outlen; |
| | } |
| |
|
| | |
| | if (ctx->ctx.base58.size) |
| | ctx->ctx.base58.buf[ctx->ctx.base58.size] = '\0'; |
| |
|
| | bool ret = base58_decode ((char *)ctx->ctx.base58.buf, ctx->ctx.base58.size, |
| | *out, outlen); |
| |
|
| | free (ctx->ctx.base58.buf); |
| | ctx->ctx.base58.buf = nullptr; |
| |
|
| | return ret; |
| | } |
| |
|
| | #endif |
| |
|
| |
|
| |
|
| | static void |
| | wrap_write (char const *buffer, idx_t len, |
| | idx_t wrap_column, idx_t *current_column, FILE *out) |
| | { |
| | if (wrap_column == 0) |
| | { |
| | |
| | if (fwrite (buffer, 1, len, stdout) < len) |
| | write_error (); |
| | } |
| | else |
| | for (idx_t written = 0; written < len; ) |
| | { |
| | idx_t to_write = MIN (wrap_column - *current_column, len - written); |
| |
|
| | if (to_write == 0) |
| | { |
| | if (fputc ('\n', out) == EOF) |
| | write_error (); |
| | *current_column = 0; |
| | } |
| | else |
| | { |
| | if (fwrite (buffer + written, 1, to_write, stdout) < to_write) |
| | write_error (); |
| | *current_column += to_write; |
| | written += to_write; |
| | } |
| | } |
| | } |
| |
|
| | static _Noreturn void |
| | finish_and_exit (FILE *in, char const *infile) |
| | { |
| | if (fclose (in) != 0) |
| | { |
| | if (streq (infile, "-")) |
| | error (EXIT_FAILURE, errno, _("closing standard input")); |
| | else |
| | error (EXIT_FAILURE, errno, "%s", quotef (infile)); |
| | } |
| |
|
| | exit (EXIT_SUCCESS); |
| | } |
| |
|
| | static _Noreturn void |
| | do_encode (FILE *in, char const *infile, FILE *out, idx_t wrap_column) |
| | { |
| | idx_t current_column = 0; |
| | char *inbuf, *outbuf; |
| | idx_t sum; |
| |
|
| | inbuf = xmalloc (ENC_BLOCKSIZE); |
| | outbuf = xmalloc (BASE_LENGTH (ENC_BLOCKSIZE)); |
| |
|
| | #if BASE_TYPE == 42 |
| | |
| | struct base_encode_context encode_ctx; |
| | bool use_ctx = (base_encode_ctx_init != nullptr); |
| | if (use_ctx) |
| | base_encode_ctx_init (&encode_ctx); |
| | #endif |
| |
|
| | do |
| | { |
| | idx_t n; |
| |
|
| | sum = 0; |
| | do |
| | { |
| | n = fread (inbuf + sum, 1, ENC_BLOCKSIZE - sum, in); |
| | sum += n; |
| | } |
| | while (!feof (in) && !ferror (in) && sum < ENC_BLOCKSIZE); |
| |
|
| | if (sum > 0) |
| | { |
| | #if BASE_TYPE == 42 |
| | if (use_ctx) |
| | { |
| | idx_t outlen = 0; |
| | base_encode_ctx (&encode_ctx, inbuf, sum, outbuf, &outlen); |
| |
|
| | wrap_write (outbuf, outlen, wrap_column, ¤t_column, out); |
| | } |
| | else |
| | #endif |
| | { |
| | |
| | |
| | base_encode (inbuf, sum, outbuf, BASE_LENGTH (sum)); |
| |
|
| | wrap_write (outbuf, BASE_LENGTH (sum), wrap_column, |
| | ¤t_column, out); |
| | } |
| | } |
| | } |
| | while (!feof (in) && !ferror (in) && sum == ENC_BLOCKSIZE); |
| |
|
| | #if BASE_TYPE == 42 |
| | if (use_ctx && base_encode_ctx_finalize) |
| | { |
| | idx_t outlen = BASE_LENGTH (ENC_BLOCKSIZE); |
| | base_encode_ctx_finalize (&encode_ctx, &outbuf, &outlen); |
| |
|
| | wrap_write (outbuf, outlen, wrap_column, ¤t_column, out); |
| | } |
| | #endif |
| |
|
| | |
| | if (wrap_column && current_column > 0 && fputc ('\n', out) == EOF) |
| | write_error (); |
| |
|
| | if (ferror (in)) |
| | error (EXIT_FAILURE, errno, _("read error")); |
| |
|
| | finish_and_exit (in, infile); |
| | } |
| |
|
| | static _Noreturn void |
| | do_decode (FILE *in, char const *infile, FILE *out, bool ignore_garbage) |
| | { |
| | char *inbuf, *outbuf; |
| | idx_t sum; |
| | struct base_decode_context ctx; |
| |
|
| | inbuf = xmalloc (BASE_LENGTH (DEC_BLOCKSIZE)); |
| | outbuf = xmalloc (DEC_BLOCKSIZE); |
| |
|
| | #if BASE_TYPE == 42 |
| | ctx.inbuf = nullptr; |
| | #endif |
| | base_decode_ctx_init (&ctx); |
| |
|
| | do |
| | { |
| | bool ok; |
| |
|
| | sum = 0; |
| | do |
| | { |
| | idx_t n = fread (inbuf + sum, |
| | 1, BASE_LENGTH (DEC_BLOCKSIZE) - sum, in); |
| |
|
| | if (ignore_garbage) |
| | { |
| | for (idx_t i = 0; n > 0 && i < n;) |
| | { |
| | if (isubase (inbuf[sum + i]) |
| | || (REQUIRED_PADDING (1) && inbuf[sum + i] == '=')) |
| | i++; |
| | else |
| | memmove (inbuf + sum + i, inbuf + sum + i + 1, --n - i); |
| | } |
| | } |
| |
|
| | sum += n; |
| |
|
| | if (ferror (in)) |
| | error (EXIT_FAILURE, errno, _("read error")); |
| | } |
| | while (sum < BASE_LENGTH (DEC_BLOCKSIZE) && !feof (in)); |
| |
|
| | while (sum || feof (in)) |
| | { |
| | idx_t n = DEC_BLOCKSIZE; |
| | if (sum) |
| | ok = base_decode_ctx (&ctx, inbuf, sum, outbuf, &n); |
| | else |
| | ok = base_decode_ctx_finalize (&ctx, &outbuf, &n); |
| |
|
| | if (fwrite (outbuf, 1, n, out) < n) |
| | write_error (); |
| |
|
| | if (! ok) |
| | error (EXIT_FAILURE, 0, _("invalid input")); |
| |
|
| | if (sum == 0) |
| | break; |
| | sum = 0; |
| | } |
| | } |
| | while (!feof (in)); |
| |
|
| | finish_and_exit (in, infile); |
| | } |
| |
|
| | int |
| | main (int argc, char **argv) |
| | { |
| | int opt; |
| | FILE *input_fh; |
| | char const *infile; |
| |
|
| | |
| | bool decode = false; |
| | |
| | bool ignore_garbage = false; |
| | |
| | idx_t wrap_column = 76; |
| |
|
| | #if BASE_TYPE == 42 |
| | int base_type = 0; |
| | #endif |
| |
|
| | initialize_main (&argc, &argv); |
| | set_program_name (argv[0]); |
| | setlocale (LC_ALL, ""); |
| | bindtextdomain (PACKAGE, LOCALEDIR); |
| | textdomain (PACKAGE); |
| |
|
| | atexit (close_stdout); |
| |
|
| | while ((opt = getopt_long (argc, argv, "diw:", long_options, nullptr)) != -1) |
| | switch (opt) |
| | { |
| | case 'd': |
| | decode = true; |
| | break; |
| |
|
| | case 'w': |
| | { |
| | intmax_t w; |
| | strtol_error s_err = xstrtoimax (optarg, nullptr, 10, &w, ""); |
| | if (LONGINT_OVERFLOW < s_err || w < 0) |
| | error (EXIT_FAILURE, 0, "%s: %s", |
| | _("invalid wrap size"), quote (optarg)); |
| | wrap_column = s_err == LONGINT_OVERFLOW || IDX_MAX < w ? 0 : w; |
| | } |
| | break; |
| |
|
| | case 'i': |
| | ignore_garbage = true; |
| | break; |
| |
|
| | #if BASE_TYPE == 42 |
| | case BASE64_OPTION: |
| | case BASE64URL_OPTION: |
| | case BASE32_OPTION: |
| | case BASE32HEX_OPTION: |
| | case BASE16_OPTION: |
| | case BASE2MSBF_OPTION: |
| | case BASE2LSBF_OPTION: |
| | case Z85_OPTION: |
| | case BASE58_OPTION: |
| | base_type = opt; |
| | break; |
| | #endif |
| |
|
| | case_GETOPT_HELP_CHAR; |
| |
|
| | case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); |
| |
|
| | default: |
| | usage (EXIT_FAILURE); |
| | break; |
| | } |
| |
|
| | #if BASE_TYPE == 42 |
| | required_padding = no_required_padding; |
| | has_padding = no_padding; |
| | get_pending_length = no_pending_length; |
| | base_decode_ctx_finalize = decode_ctx_finalize; |
| |
|
| | switch (base_type) |
| | { |
| | case BASE64_OPTION: |
| | base_length = base64_length_wrapper; |
| | required_padding = base64_required_padding; |
| | has_padding = base64_ctx_has_padding; |
| | get_pending_length = base64_ctx_get_pending_length; |
| | isubase = isubase64; |
| | base_encode = base64_encode; |
| | base_decode_ctx_init = base64_decode_ctx_init_wrapper; |
| | base_decode_ctx = base64_decode_ctx_wrapper; |
| | break; |
| |
|
| | case BASE64URL_OPTION: |
| | base_length = base64_length_wrapper; |
| | required_padding = base64_required_padding; |
| | has_padding = base64_ctx_has_padding; |
| | get_pending_length = base64_ctx_get_pending_length; |
| | isubase = isubase64url; |
| | base_encode = base64url_encode; |
| | base_decode_ctx_init = base64url_decode_ctx_init_wrapper; |
| | base_decode_ctx = base64url_decode_ctx_wrapper; |
| | break; |
| |
|
| | case BASE32_OPTION: |
| | base_length = base32_length_wrapper; |
| | required_padding = base32_required_padding; |
| | has_padding = base32_ctx_has_padding; |
| | get_pending_length = base32_ctx_get_pending_length; |
| | isubase = isubase32; |
| | base_encode = base32_encode; |
| | base_decode_ctx_init = base32_decode_ctx_init_wrapper; |
| | base_decode_ctx = base32_decode_ctx_wrapper; |
| | break; |
| |
|
| | case BASE32HEX_OPTION: |
| | base_length = base32_length_wrapper; |
| | required_padding = base32_required_padding; |
| | has_padding = base32_ctx_has_padding; |
| | get_pending_length = base32_ctx_get_pending_length; |
| | isubase = isubase32hex; |
| | base_encode = base32hex_encode; |
| | base_decode_ctx_init = base32hex_decode_ctx_init_wrapper; |
| | base_decode_ctx = base32hex_decode_ctx_wrapper; |
| | break; |
| |
|
| | case BASE16_OPTION: |
| | base_length = base16_length; |
| | get_pending_length = base16_ctx_get_pending_length; |
| | isubase = isubase16; |
| | base_encode = base16_encode; |
| | base_decode_ctx_init = base16_decode_ctx_init; |
| | base_decode_ctx = base16_decode_ctx; |
| | break; |
| |
|
| | case BASE2MSBF_OPTION: |
| | base_length = base2_length; |
| | get_pending_length = base2_ctx_get_pending_length; |
| | isubase = isubase2; |
| | base_encode = base2msbf_encode; |
| | base_decode_ctx_init = base2_decode_ctx_init; |
| | base_decode_ctx = base2msbf_decode_ctx; |
| | break; |
| |
|
| | case BASE2LSBF_OPTION: |
| | base_length = base2_length; |
| | get_pending_length = base2_ctx_get_pending_length; |
| | isubase = isubase2; |
| | base_encode = base2lsbf_encode; |
| | base_decode_ctx_init = base2_decode_ctx_init; |
| | base_decode_ctx = base2lsbf_decode_ctx; |
| | break; |
| |
|
| | case Z85_OPTION: |
| | base_length = z85_length; |
| | get_pending_length = z85_ctx_get_pending_length; |
| | isubase = isuz85; |
| | base_encode = z85_encode; |
| | base_decode_ctx_init = z85_decode_ctx_init; |
| | base_decode_ctx = z85_decode_ctx; |
| | break; |
| |
|
| | case BASE58_OPTION: |
| | base_length = base58_length; |
| | isubase = isubase58; |
| | base_encode_ctx_init = base58_encode_ctx_init; |
| | base_encode_ctx = base58_encode_ctx; |
| | base_encode_ctx_finalize = base58_encode_ctx_finalize; |
| | base_decode_ctx_init = base58_decode_ctx_init; |
| | base_decode_ctx = base58_decode_ctx; |
| | base_decode_ctx_finalize = base58_decode_ctx_finalize; |
| | break; |
| |
|
| | default: |
| | error (0, 0, _("missing encoding type")); |
| | usage (EXIT_FAILURE); |
| | } |
| | #endif |
| |
|
| | if (argc - optind > 1) |
| | { |
| | error (0, 0, _("extra operand %s"), quote (argv[optind + 1])); |
| | usage (EXIT_FAILURE); |
| | } |
| |
|
| | if (optind < argc) |
| | infile = argv[optind]; |
| | else |
| | infile = "-"; |
| |
|
| | if (streq (infile, "-")) |
| | { |
| | xset_binary_mode (STDIN_FILENO, O_BINARY); |
| | input_fh = stdin; |
| | } |
| | else |
| | { |
| | input_fh = fopen (infile, "rb"); |
| | if (input_fh == nullptr) |
| | error (EXIT_FAILURE, errno, "%s", quotef (infile)); |
| | } |
| |
|
| | fadvise (input_fh, FADVISE_SEQUENTIAL); |
| |
|
| | if (decode) |
| | do_decode (input_fh, infile, stdout, ignore_garbage); |
| | else |
| | do_encode (input_fh, infile, stdout, wrap_column); |
| | } |
| |
|