--- Makefile | 3 + README | 3 + base16.1 | 40 ++++++++++++ base16.c | 168 +++++++++++++++++++++++++++++++++++++++++++++++++ base32.1 | 40 ++++++++++++ base32.c | 214 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ base64.1 | 40 ++++++++++++ base64.c | 198 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 706 insertions(+) create mode 100644 base16.1 create mode 100644 base16.c create mode 100644 base32.1 create mode 100644 base32.c create mode 100644 base64.1 create mode 100644 base64.c diff --git a/Makefile b/Makefile index 6b2bfdf..9600639 100644 --- a/Makefile +++ b/Makefile _AT_@ -84,6 +84,9 @@ LIBUTILSRC =\ LIB = $(LIBUTF) $(LIBUTIL) BIN =\ + base16\ + base32\ + base64\ basename\ cal\ cat\ diff --git a/README b/README index d60d8fc..ebc20a4 100644 --- a/README +++ b/README _AT_@ -12,6 +12,9 @@ The following tools are implemented: UTILITY MISSING ------- ------- +0=* x base16 . +0=* x base32 . +0=* x base64 . 0=*|o basename . 0=*|o cal . 0=*|o cat . diff --git a/base16.1 b/base16.1 new file mode 100644 index 0000000..2debf6a --- /dev/null +++ b/base16.1 _AT_@ -0,0 +1,40 @@ +.Dd 2016-03-29 +.Dt BASE16 1 +.Os sbase +.Sh NAME +.Nm base16 +.Nd encode data in or decode data from base16 +.Sh SYNOPSIS +.Nm +.Op Fl di +.Op Fl w Ar cols +.Op Ar file +.Sh DESCRIPTION +.Nm +read the +.Ar file +in either encode the file in base16 (default) +or decode it from base16 +.Op Fl d . +If no +.Ar file +is given +.Nm +reads from stdin. +.Sh OPTIONS +.Bl -tag -width Ds +.It Fl d +Decode instead of encode. +.It Fl i +Ignore garbage if decode. <newline> is always ignored. +.It Fl w Ar cols +Wrap the output at +.Ar cols +columns (default 76). If +.Ar cols +is zero, do not wrap. +.El +.Sh STANDARDS +The output of the +.Nm +utility is compliant with the RFC 4648 specification. diff --git a/base16.c b/base16.c new file mode 100644 index 0000000..9940a02 --- /dev/null +++ b/base16.c _AT_@ -0,0 +1,168 @@ +/* See LICENSE file for copyright and license details. */ +#include <fcntl.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "util.h" + +#define ALPHABET "0123456789ABCDEF" +#define ALTALPHABET "0123456789ABCDEF" + +static unsigned char lut[256] = + ALPHABET ALPHABET ALPHABET ALPHABET ALPHABET ALPHABET ALPHABET ALPHABET + ALPHABET ALPHABET ALPHABET ALPHABET ALPHABET ALPHABET ALPHABET ALPHABET; +static int iflag = 0; +static size_t cols; +static size_t pos = 0; +static size_t (*output)(const void *restrict, size_t, size_t, FILE *); + +static size_t +wrapwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *stream) +{ + const char *restrict buf = ptr; + size_t n = cols - pos; + + if (nitems >= n) { + fwrite(buf, 1, n, stream); + nitems -= n; + buf += n; + pos = 0; + fputc('\n', stdout); + } + + while (nitems >= cols) { + fwrite(buf, 1, cols, stream); + nitems -= cols; + buf += cols; + fputc('\n', stdout); + } + + if (nitems) { + fwrite(buf, 1, nitems, stream); + pos = nitems; + } + + (void) size; + return 0; +} + +static void +encode(FILE *fp) +{ + unsigned char ibuf[BUFSIZ / 2]; + unsigned char obuf[sizeof(ibuf) * 2]; + register unsigned char *p, *out; + unsigned char *pend; + size_t n; + + while ((n = fread(ibuf, 1, sizeof(ibuf), fp))) { + out = obuf; + for (p = ibuf, pend = p + n; p != pend; p += 1, out += 2) { + out[0] = lut[*p >> 4]; + out[1] = lut[*p]; + } + output(obuf, 1, n << 1, stdout); + } + + if (pos) + fputc('\n', stdout); +} + +static void +decode(FILE *fp) +{ + unsigned char ibuf[BUFSIZ / 2]; + unsigned char obuf[BUFSIZ / 2 - ((BUFSIZ / 2) % 2)]; + unsigned char jbuf[2]; + unsigned char value; + size_t i, j = 0, n, o = 0; + register unsigned char *p; + + memset(lut, ~0, sizeof(lut)); + for (i = 0; i < 16; i++) { + lut[(int)(ALPHABET[i])] = i; + lut[(int)(ALTALPHABET[i])] = i; + } + + while ((n = fread(ibuf, 1, sizeof(ibuf), fp))) { + for (p = ibuf; n--; p++) { + value = lut[*p]; + if (value == 0xFF) { + if (*p == '\n') + continue; + else if (iflag) + continue; + else + eprintf("invalid input\n"); + } + jbuf[j++] = value; + if (j == 2) { + j = 0; + obuf[o++] = (jbuf[0] << 4) | jbuf[1]; + if (o == sizeof(obuf)) { + fwrite(obuf, 1, o, stdout); + o = 0; + } + } + } + } + if (j && feof(fp)) + eprintf("invalid input\n"); + if (o) + fwrite(obuf, 1, o, stdout); +} + +static void +usage(void) +{ + /* Logically, it should be [-d [-i] | -w col], but + * for consistency we let it be [-di] [-w col]. */ + + eprintf("usage: %s [-di] [-w col] [file]\n", argv0); +} + +int +main(int argc, char *argv[]) +{ + int dflag = 0; + long wflag = -1; + FILE *fp = stdin; + char *path = "<stdin>"; + + ARGBEGIN { + case 'd': + dflag = 1; + break; + case 'i': + iflag = 1; + break; + case 'w': + wflag = estrtonum(EARGF(usage()), 0, LONG_MAX); + break; + default: + usage(); + } ARGEND + + if (argc > 1) + usage(); + + if (argc && strcmp(*argv, "-")) { + path = *argv; + if (!(fp = fopen(*argv, "r"))) + eprintf("fopen %s:", *argv); + } + + if (wflag == 0) { + output = &fwrite; + pos = 1; + } else { + output = &wrapwrite; + cols = wflag > 0 ? wflag : 76; + } + + (dflag ? decode : encode)(fp); + return fshut(fp, path) || fshut(stdout, "<stdout>"); +} diff --git a/base32.1 b/base32.1 new file mode 100644 index 0000000..51a279a --- /dev/null +++ b/base32.1 _AT_@ -0,0 +1,40 @@ +.Dd 2016-03-29 +.Dt BASE32 1 +.Os sbase +.Sh NAME +.Nm base32 +.Nd encode data in or decode data from base32 +.Sh SYNOPSIS +.Nm +.Op Fl di +.Op Fl w Ar cols +.Op Ar file +.Sh DESCRIPTION +.Nm +read the +.Ar file +in either encode the file in base32 (default) +or decode it from base32 +.Op Fl d . +If no +.Ar file +is given +.Nm +reads from stdin. +.Sh OPTIONS +.Bl -tag -width Ds +.It Fl d +Decode instead of encode. +.It Fl i +Ignore garbage if decode. <newline> is always ignored. +.It Fl w Ar cols +Wrap the output at +.Ar cols +columns (default 76). If +.Ar cols +is zero, do not wrap. +.El +.Sh STANDARDS +The output of the +.Nm +utility is compliant with the RFC 4648 specification. diff --git a/base32.c b/base32.c new file mode 100644 index 0000000..49457e0 --- /dev/null +++ b/base32.c _AT_@ -0,0 +1,214 @@ +/* See LICENSE file for copyright and license details. */ +#include <fcntl.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "util.h" + +#define ALPHABET "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567" + +static unsigned char lut[256] = ALPHABET ALPHABET ALPHABET ALPHABET ALPHABET ALPHABET ALPHABET ALPHABET; +static int iflag = 0; +static size_t cols; +static size_t pos = 0; +static size_t (*output)(const void *restrict, size_t, size_t, FILE *); + +static size_t +wrapwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *stream) +{ + const char *restrict buf = ptr; + size_t n = cols - pos; + + if (nitems >= n) { + fwrite(buf, 1, n, stream); + nitems -= n; + buf += n; + pos = 0; + fputc('\n', stdout); + } + + while (nitems >= cols) { + fwrite(buf, 1, cols, stream); + nitems -= cols; + buf += cols; + fputc('\n', stdout); + } + + if (nitems) { + fwrite(buf, 1, nitems, stream); + pos = nitems; + } + + (void) size; + return 0; +} + +static void +encode(FILE *fp) +{ + unsigned char ibuf[(BUFSIZ / 2) - ((BUFSIZ / 2) % 5)]; + unsigned char obuf[sizeof(ibuf) / 5 * 8]; + register unsigned char *p, *out; + unsigned char *pend; + size_t n, o; + + do { + for (o = 0; o < sizeof(ibuf); o += n) + if (!(n = fread(ibuf + o, 1, sizeof(ibuf) - o, fp))) + break; + if (!o) + goto end; + n = o; + o %= 5; + out = obuf; + for (p = ibuf, pend = p + n - o; p != pend; p += 5, out += 8) { + out[0] = lut[p[0] >> 3]; + out[1] = lut[(unsigned char)(p[0] << 2) | (p[1] >> 6)]; + out[2] = lut[p[1] >> 1]; + out[3] = lut[(unsigned char)(p[1] << 4) | (p[2] >> 4)]; + out[4] = lut[(unsigned char)(p[2] << 1) | (p[3] >> 7)]; + out[5] = lut[p[3] >> 2]; + out[6] = lut[(unsigned char)(p[3] << 3) | (p[4] >> 5)]; + out[7] = lut[p[4]]; + } + n = (size_t)(out - obuf); + output(obuf, 1, n, stdout); + } while (!o); + + /* This part is only reached if padding is required. { */ + + memset(obuf, '=', 8); + memset(p + o, 0, 8 - o); + obuf[0] = lut[p[0] >> 3]; + obuf[1] = lut[(unsigned char)(p[0] << 2) | (p[1] >> 6)]; + if (o == 1) goto done; + obuf[2] = lut[p[1] >> 1]; + obuf[3] = lut[(unsigned char)(p[1] << 4) | (p[2] >> 4)]; + if (o == 2) goto done; + obuf[4] = lut[(unsigned char)(p[2] << 1) | (p[3] >> 7)]; + if (o == 3) goto done; + obuf[5] = lut[p[3] >> 2]; + obuf[6] = lut[(unsigned char)(p[3] << 3)]; +done: + output(obuf, 1, 8, stdout); + + /* } */ + +end: + if (pos) + fputc('\n', stdout); +} + +static void +decode(FILE *fp) +{ + unsigned char ibuf[BUFSIZ / 2]; + unsigned char obuf[BUFSIZ / 2 - ((BUFSIZ / 2) % 5)]; + unsigned char jbuf[8]; + unsigned char value; + size_t i, j = 0, n, o = 0, pads = 0, erasure; + register unsigned char *p; + static const int pads_to_erasure[] = {0, 1, -1, 2, 3, -1, 4, -1}; + + memset(lut, ~0, sizeof(lut)); + for (i = 0; i < 32; i++) + lut[(int)(ALPHABET[i])] = i; + + while ((n = fread(ibuf, 1, sizeof(ibuf), fp))) { + for (p = ibuf; n--; p++) { + value = lut[*p]; + if (value == 0xFF) { + if (*p == '=') { + if (++pads > 6) + eprintf("1 invalid input\n"); + value = 0; + } else if (*p == '\n') { + continue; + } else if (pads) { + eprintf("invalid input\n"); + } else if (iflag) { + continue; + } else { + eprintf("invalid input\n"); + } + } + jbuf[j++] = value; + if (j == 8) { + j = 0; + obuf[o++] = (jbuf[0] << 3) | (jbuf[1] >> 2); + obuf[o++] = (jbuf[1] << 6) | (jbuf[2] << 1) | (jbuf[3] >> 4); + obuf[o++] = (jbuf[3] << 4) | (jbuf[4] >> 1); + obuf[o++] = (jbuf[4] << 7) | (jbuf[5] << 2) | (jbuf[6] >> 3); + obuf[o++] = (jbuf[6] << 5) | (jbuf[7] >> 0); + + if (o == sizeof(obuf) && !pads) { + fwrite(obuf, 1, o, stdout); + o = 0; + } + } + } + } + if (j && feof(fp)) + eprintf("invalid input\n"); + if (o) { + erasure = pads_to_erasure[pads]; + if (erasure < 0) + eprintf("invalid input\n"); + fwrite(obuf, 1, o - erasure, stdout); + } +} + +static void +usage(void) +{ + /* Logically, it should be [-d [-i] | -w col], but + * for compatibility we let it be [-di] [-w col]. */ + + eprintf("usage: %s [-di] [-w col] [file]\n", argv0); +} + +int +main(int argc, char *argv[]) +{ + int dflag = 0; + long wflag = -1; + FILE *fp = stdin; + char *path = "<stdin>"; + + ARGBEGIN { + case 'd': + dflag = 1; + break; + case 'i': + iflag = 1; + break; + case 'w': + wflag = estrtonum(EARGF(usage()), 0, LONG_MAX); + break; + default: + usage(); + } ARGEND + + if (argc > 1) + usage(); + + if (argc && strcmp(*argv, "-")) { + path = *argv; + if (!(fp = fopen(*argv, "r"))) + eprintf("fopen %s:", *argv); + } + + if (wflag == 0) { + output = &fwrite; + pos = 1; + } else { + output = &wrapwrite; + cols = wflag > 0 ? wflag : 76; + } + + (dflag ? decode : encode)(fp); + return fshut(fp, path) || fshut(stdout, "<stdout>"); +} diff --git a/base64.1 b/base64.1 new file mode 100644 index 0000000..d857784 --- /dev/null +++ b/base64.1 _AT_@ -0,0 +1,40 @@ +.Dd 2016-03-29 +.Dt BASE64 1 +.Os sbase +.Sh NAME +.Nm base64 +.Nd encode data in or decode data from base64 +.Sh SYNOPSIS +.Nm +.Op Fl di +.Op Fl w Ar cols +.Op Ar file +.Sh DESCRIPTION +.Nm +read the +.Ar file +in either encode the file in base64 (default) +or decode it from base64 +.Op Fl d . +If no +.Ar file +is given +.Nm +reads from stdin. +.Sh OPTIONS +.Bl -tag -width Ds +.It Fl d +Decode instead of encode. +.It Fl i +Ignore garbage if decode. <newline> is always ignored. +.It Fl w Ar cols +Wrap the output at +.Ar cols +columns (default 76). If +.Ar cols +is zero, do not wrap. +.El +.Sh STANDARDS +The output of the +.Nm +utility is compliant with the RFC 4648 specification. diff --git a/base64.c b/base64.c new file mode 100644 index 0000000..4dfc25b --- /dev/null +++ b/base64.c _AT_@ -0,0 +1,198 @@ +/* See LICENSE file for copyright and license details. */ +#include <fcntl.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "util.h" + +#define ALPHABET "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + +static unsigned char lut[256] = ALPHABET ALPHABET ALPHABET ALPHABET; +static int iflag = 0; +static size_t cols; +static size_t pos = 0; +static size_t (*output)(const void *restrict, size_t, size_t, FILE *); + +static size_t +wrapwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *stream) +{ + const char *restrict buf = ptr; + size_t n = cols - pos; + + if (nitems >= n) { + fwrite(buf, 1, n, stream); + nitems -= n; + buf += n; + pos = 0; + fputc('\n', stdout); + } + + while (nitems >= cols) { + fwrite(buf, 1, cols, stream); + nitems -= cols; + buf += cols; + fputc('\n', stdout); + } + + if (nitems) { + fwrite(buf, 1, nitems, stream); + pos = nitems; + } + + (void) size; + return 0; +} + +static void +encode(FILE *fp) +{ + unsigned char ibuf[(BUFSIZ / 2) - ((BUFSIZ / 2) % 3)]; + unsigned char obuf[sizeof(ibuf) / 3 * 4]; + register unsigned char *p, *out; + unsigned char *pend; + size_t n, o; + + do { + for (o = 0; o < sizeof(ibuf); o += n) + if (!(n = fread(ibuf + o, 1, sizeof(ibuf) - o, fp))) + break; + if (!o) + goto end; + n = o; + o %= 3; + out = obuf; + for (p = ibuf, pend = p + n - o; p != pend; p += 3, out += 4) { + out[0] = lut[p[0] >> 2]; + out[1] = lut[(unsigned char)(p[0] << 4) | (p[1] >> 4)]; + out[2] = lut[(unsigned char)(p[1] << 2) | (p[2] >> 6)]; + out[3] = lut[p[2]]; + } + n = (size_t)(out - obuf); + output(obuf, 1, n, stdout); + } while (!o); + + /* This part is only reached if padding is required. { */ + + obuf[0] = lut[p[0] >> 2]; + if (o == 1) { + obuf[1] = lut[(unsigned char)(p[0] << 4)]; + obuf[2] = '='; + } else { + obuf[1] = lut[(unsigned char)(p[0] << 4) | (p[1] >> 4)]; + obuf[2] = lut[(unsigned char)(p[1] << 2)]; + } + obuf[3] = '='; + output(obuf, 1, 4, stdout); + + /* } */ + +end: + if (pos) + fputc('\n', stdout); +} + +static void +decode(FILE *fp) +{ + unsigned char ibuf[BUFSIZ / 2]; + unsigned char obuf[BUFSIZ / 2 - ((BUFSIZ / 2) % 3)]; + unsigned char jbuf[4]; + unsigned char value; + size_t i, j = 0, n, o = 0, pads = 0; + register unsigned char *p; + + memset(lut, ~0, sizeof(lut)); + for (i = 0; i < 64; i++) + lut[(int)(ALPHABET[i])] = i; + + while ((n = fread(ibuf, 1, sizeof(ibuf), fp))) { + for (p = ibuf; n--; p++) { + value = lut[*p]; + if (value == 0xFF) { + if (*p == '=') { + if (++pads > 2) + eprintf("invalid input\n"); + value = 0; + } else if (*p == '\n') { + continue; + } else if (pads) { + eprintf("invalid input\n"); + } else if (iflag) { + continue; + } else { + eprintf("invalid input\n"); + } + } + jbuf[j++] = value; + if (j == 4) { + j = 0; + obuf[o++] = (jbuf[0] << 2) | (jbuf[1] >> 4); + obuf[o++] = (jbuf[1] << 4) | (jbuf[2] >> 2); + obuf[o++] = (jbuf[2] << 6) | (jbuf[3] >> 0); + if (o == sizeof(obuf)) { + fwrite(obuf, 1, o - pads, stdout); + o = 0; + } + } + } + } + if (j && feof(fp)) + eprintf("invalid input\n"); + if (o) + fwrite(obuf, 1, o - pads, stdout); +} + +static void +usage(void) +{ + /* Logically, it should be [-d [-i] | -w col], but + * for compatibility we let it be [-di] [-w col]. */ + + eprintf("usage: %s [-di] [-w col] [file]\n", argv0); +} + +int +main(int argc, char *argv[]) +{ + int dflag = 0; + long wflag = -1; + FILE *fp = stdin; + char *path = "<stdin>"; + + ARGBEGIN { + case 'd': + dflag = 1; + break; + case 'i': + iflag = 1; + break; + case 'w': + wflag = estrtonum(EARGF(usage()), 0, LONG_MAX); + break; + default: + usage(); + } ARGEND + + if (argc > 1) + usage(); + + if (argc && strcmp(*argv, "-")) { + path = *argv; + if (!(fp = fopen(*argv, "r"))) + eprintf("fopen %s:", *argv); + } + + if (wflag == 0) { + output = &fwrite; + pos = 1; + } else { + output = &wrapwrite; + cols = wflag > 0 ? wflag : 76; + } + + (dflag ? decode : encode)(fp); + return fshut(fp, path) || fshut(stdout, "<stdout>"); +} -- 2.7.4Received on Tue Mar 29 2016 - 18:59:24 CEST
This archive was generated by hypermail 2.3.0 : Tue Mar 29 2016 - 19:00:19 CEST