Tiny base64 encoder/decoder command patterned after the linux and the macosx

ones with the same name,.
This commit is contained in:
christos 2018-07-24 15:26:16 +00:00
parent a16788053a
commit 0d2d986001
4 changed files with 363 additions and 2 deletions

View File

@ -1,10 +1,10 @@
# $NetBSD: Makefile,v 1.231 2018/07/13 11:14:14 maxv Exp $
# $NetBSD: Makefile,v 1.232 2018/07/24 15:26:16 christos Exp $
# from: @(#)Makefile 8.3 (Berkeley) 1/7/94
.include <bsd.own.mk>
SUBDIR= apply asa at audio audiocfg \
banner basename biff bthset btkey btpin \
banner base64 basename biff bthset btkey btpin \
bzip2 bzip2recover c11 c89 c99 cal calendar cap_mkdb cdplay \
checknr chflags chpass cksum cmp cleantags col colcrt colrm \
column comm compress config crunch csplit ctags cut cvslatest \

9
usr.bin/base64/Makefile Normal file
View File

@ -0,0 +1,9 @@
# $NetBSD: Makefile,v 1.1 2018/07/24 15:26:16 christos Exp $
WARNS?= 6
.include <bsd.own.mk>
PROG= base64
.include <bsd.prog.mk>

74
usr.bin/base64/base64.1 Normal file
View File

@ -0,0 +1,74 @@
.\" $NetBSD: base64.1,v 1.1 2018/07/24 15:26:16 christos Exp $
.\"
.\" Copyright (c) 2018 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" This code is derived from software contributed to The NetBSD Foundation
.\" by Christos Zoulas.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.\"
.Dd July 24, 2018
.Dt base64 1
.Os
.Sh NAME
.Nm base64
.Nd base64 encode/decode data into the stardard output
.Sh SYNOPSIS
.Nm
.Op Fl di
.Op Fl w Ar wrap
.Op Ar
.Sh DESCRIPTION
.Nm
reads from the standard input or from each file argument, and encodes
or decodes data based on the base64 scheme described in RFC 3548 into
the standard output.
.Pp
The following options are available:
.Bl -tag -width XXXXXXX
.It Fl d
Decode the input instead of encoding it.
.It Fl i
Ignore whitespace characters when decoding.
.It Fl w Ar wrap
Wrap lines longer than
.Ar wrap
characters using a newline.
The default number of characters is 76.
.El
.Sh EXIT STATUS
.Nm
exits with 0 if there was no error and non-zero if it could not encode or
decode, printing an error message.
.Sh SEE ALSO
.Xr b64_ntop ,
.Xr b64_pton .
.Sh AUTHORS
Christos Zoulas
.Sh HISTORY
The
.Nm
command first appeared on
Linux ?, MacOS/X ?, and
.Nx 9 .

278
usr.bin/base64/base64.c Normal file
View File

@ -0,0 +1,278 @@
/* $NetBSD: base64.c,v 1.1 2018/07/24 15:26:16 christos Exp $ */
/*-
* Copyright (c) 2018 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Christos Zoulas.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: base64.c,v 1.1 2018/07/24 15:26:16 christos Exp $");
#include <ctype.h>
#include <errno.h>
#include <err.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static const char B64[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static size_t
getinput(FILE *fin, uint8_t in[3])
{
size_t res;
int c;
for (res = 0; res < 3 && (c = getc(fin)) != EOF; res++)
in[res] = (uint8_t)c;
for (size_t i = res; i < 3; i++)
in[i] = 0;
return res;
}
static int
putoutput(FILE *fout, uint8_t out[4], size_t len, size_t wrap, size_t *pos)
{
size_t i;
for (i = 0; i < len + 1; i++) {
if (out[i] >= 64) {
errno = EINVAL;
return -1;
}
if (fputc(B64[out[i]], fout) == -1)
return -1;
if (++(*pos) == wrap) {
if (fputc('\n', fout) == -1)
return -1;
*pos = 0;
}
}
for (; i < 4; i++) {
if (fputc('=', fout) == -1)
return -1;
if (++(*pos) == wrap) {
if (fputc('\n', fout) == -1)
return -1;
*pos = 0;
}
}
return 0;
}
static void
encode(uint8_t out[4], uint8_t in[3])
{
out[0] = in[0] >> 2;
out[1] = (uint8_t)(((in[0] & 0x03) << 4) | (in[1] >> 4));
out[2] = (uint8_t)(((in[1] & 0x0f) << 2) | (in[2] >> 6));
out[3] = in[2] & 0x3f;
}
static int
b64_encode(FILE *fout, FILE *fin, size_t wrap)
{
uint8_t in[3];
uint8_t out[4];
size_t ilen;
size_t pos = 0;
while ((ilen = getinput(fin, in)) > 2) {
encode(out, in);
if (putoutput(fout, out, ilen, wrap, &pos) == -1)
return -1;
}
if (ilen != 0) {
encode(out, in);
if (putoutput(fout, out, ilen, wrap, &pos) == -1)
return -1;
}
if (pos && wrap) {
if (fputc('\n', fout) == -1)
return -1;
}
return 0;
}
static int
b64_decode(FILE *fout, FILE *fin, bool ignore)
{
int state, c;
uint8_t b, out;
char *pos;
state = 0;
out = 0;
while ((c = getc(fin)) != -1) {
if (ignore && isspace(c))
continue;
if (c == '=')
break;
pos = strchr(B64, c);
if (pos == NULL)
return -1;
b = (uint8_t)(pos - B64);
switch (state) {
case 0:
out = (uint8_t)(b << 2);
break;
case 1:
out |= b >> 4;
if (fputc(out, fout) == -1)
return -1;
out = (uint8_t)((b & 0xf) << 4);
break;
case 2:
out |= b >> 2;
if (fputc(out, fout) == -1)
return -1;
out = (uint8_t)((b & 0x3) << 6);
break;
case 3:
out |= b;
if (fputc(out, fout) == -1)
return -1;
out = 0;
break;
default:
abort();
}
state = (state + 1) & 3;
}
if (c == '=') {
switch (state) {
case 0:
case 1:
return -1;
case 2:
while ((c = getc(fin)) != -1) {
if (ignore && isspace(c))
continue;
break;
}
if (c != '=')
return -1;
/*FALLTHROUGH*/
case 3:
while ((c = getc(fin)) != -1) {
if (ignore && isspace(c))
continue;
break;
}
if (c != -1)
return -1;
return 0;
default:
abort();
}
}
if (c != -1 || state != 0)
return -1;
return 0;
}
static __dead void
usage(void)
{
fprintf(stderr, "Usage: %s [-di] [-w <wrap>] [<file>]...\n",
getprogname());
exit(EXIT_FAILURE);
}
static void
doit(FILE *fout, FILE *fin, bool decode, bool ignore, size_t wrap)
{
int e;
if (decode)
e = b64_decode(stdout, stdin, ignore) != 0;
else
e = b64_encode(stdout, stdin, wrap) != 0;
if (e != 0)
errx(EXIT_FAILURE, "%scoding failed", decode ? "De": "En");
}
int
main(int argc, char *argv[])
{
bool decode = false;
size_t wrap = 76;
bool ignore = false;
int c;
while ((c = getopt(argc, argv, "diw:")) != -1) {
switch (c) {
case 'd':
decode = true;
break;
case 'i':
ignore = true;
break;
case 'w':
wrap = (size_t)atoi(optarg);
break;
default:
usage();
}
}
if (optind == argc) {
doit(stdout, stdin, decode, ignore, wrap);
return EXIT_SUCCESS;
}
for (c = optind; c < argc; c++) {
FILE *fp = strcmp(argv[c], "-") == 0 ?
stdin : fopen(argv[c], "r");
if (fp == NULL)
err(EXIT_FAILURE, "Can't open `%s'", argv[c]);
doit(stdout, fp, decode, ignore, wrap);
if (fp != stdin)
fclose(fp);
fclose(fp);
}
return EXIT_SUCCESS;
}