Skip to content

Instantly share code, notes, and snippets.

@atr000
Created September 8, 2010 00:28
Show Gist options
  • Save atr000/569384 to your computer and use it in GitHub Desktop.
Save atr000/569384 to your computer and use it in GitHub Desktop.
\cfg{man-identity}{base64}{1}{2004-11-20}{Simon Tatham}{Simon Tatham}
\title Man page for \cw{base64}
\U NAME
\cw{base64} - stand-alone encoder and decoder for base64
\U SYNOPSIS
\c base64 [ -d ] [ filename ]
\e bbbbbb bb iiiiiiii
\c base64 -e [ -c width ] [ filename ]
\e bbbbbb bb bb iiiii iiiiiiii
\U DESCRIPTION
\cw{base64} is a command-line utility for encoding and decoding the
\q{base64} encoding.
This encoding, defined in
\W{http://www.ietf.org/rfc/rfc2045.txt}{RFC 2045}, is primarily used
to encode binary attachments in MIME e-mail, but is widely used in
many other applications as well. For example, the \q{Content-MD5}
mail header contains a small piece of base64; SSH private keys are
generally stored as base64-encoded blobs; and so on.
Other utilities, such as \cw{munpack}, exist which will take an
entire MIME-encoded message, identify the base64-encoded subparts,
and decode them. However, these utilities will not help you if you
need to inspect a Content-MD5 header or an SSH private key.
\cw{base64} is a very simple stand-alone encoder and decoder for the
base64 format \e{alone}. It does not try to understand MIME headers
or anything other than raw data.
\U OPTIONS
By default (if neither \cw{-d} or \cw{-e} is supplied), \cw{base64}
operates in decode mode.
\dt \cw{-d}
\dd Places \cw{base64} into decode mode. In this mode, it will read
from standard input or the supplied file name, ignore all characters
that are not part of the base64 alphabet, decode the ones that are,
and output the decoded data on standard output.
\dt \cw{-e}
\dd Places \cw{base64} into encode mode. In this mode, it will read
binary data from standard input or the supplied file name, encode it
as base64, and output the encoded data on standard output.
\dt \cw{-c} \e{width}
\dd If \cw{base64} is operating in encode mode, this controls the
number of base64 characters output per line of the encoded file.
Normally base64-reading applications do not care about this, so the
default of 64 characters per line is perfectly adequate.
\lcont{
The special value 0 will prevent \cw{base64} from ever writing a
line break in the middle of the data at all.
The base64 encoding converts between a group of three plaintext
bytes and a group of four encoded bytes. \cw{base64} does not
support breaking an encoded group across a line (although it can
handle it as input if it receives it). Therefore, the \e{width}
parameter passed to \cw{-c} must be a multiple of 4.
}
\U LICENCE
\cw{base64} is free software, distributed under the MIT licence.
Type \cw{base64 --licence} to see the full licence text.
\versionid $Id$
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#define isbase64(c) ( ((c) >= 'A' && (c) <= 'Z') || \
((c) >= 'a' && (c) <= 'z') || \
((c) >= '0' && (c) <= '9') || \
(c) == '+' || (c) == '/' || (c) == '=' \
)
int base64_decode_atom(char *atom, unsigned char *out) {
int vals[4];
int i, v, len;
unsigned word;
char c;
for (i = 0; i < 4; i++) {
c = atom[i];
if (c >= 'A' && c <= 'Z')
v = c - 'A';
else if (c >= 'a' && c <= 'z')
v = c - 'a' + 26;
else if (c >= '0' && c <= '9')
v = c - '0' + 52;
else if (c == '+')
v = 62;
else if (c == '/')
v = 63;
else if (c == '=')
v = -1;
else
return 0; /* invalid atom */
vals[i] = v;
}
if (vals[0] == -1 || vals[1] == -1)
return 0;
if (vals[2] == -1 && vals[3] != -1)
return 0;
if (vals[3] != -1)
len = 3;
else if (vals[2] != -1)
len = 2;
else
len = 1;
word = ((vals[0] << 18) |
(vals[1] << 12) |
((vals[2] & 0x3F) << 6) |
(vals[3] & 0x3F));
out[0] = (word >> 16) & 0xFF;
if (len > 1)
out[1] = (word >> 8) & 0xFF;
if (len > 2)
out[2] = word & 0xFF;
return len;
}
void base64_encode_atom(unsigned char *data, int n, char *out) {
static const char base64_chars[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
unsigned word;
word = data[0] << 16;
if (n > 1)
word |= data[1] << 8;
if (n > 2)
word |= data[2];
out[0] = base64_chars[(word >> 18) & 0x3F];
out[1] = base64_chars[(word >> 12) & 0x3F];
if (n > 1)
out[2] = base64_chars[(word >> 6) & 0x3F];
else
out[2] = '=';
if (n > 2)
out[3] = base64_chars[word & 0x3F];
else
out[3] = '=';
}
const char usagemsg[] =
"usage: base64 [-d] [filename] decode from a file or from stdin\n"
" or: base64 -e [-cNNN] [filename] encode from a file or from stdin\n"
"where: -d decode mode (default)\n"
" -e encode mode\n"
" -cNNN set number of chars per line for encoded output\n"
" also: base64 --version report version number\n"
" base64 --help display this help text\n"
" base64 --licence display the (MIT) licence text\n"
;
void usage(void) {
fputs(usagemsg, stdout);
}
const char licencemsg[] =
"base64 is copyright 2001,2004 Simon Tatham.\n"
"\n"
"Permission is hereby granted, free of charge, to any person\n"
"obtaining a copy of this software and associated documentation files\n"
"(the \"Software\"), to deal in the Software without restriction,\n"
"including without limitation the rights to use, copy, modify, merge,\n"
"publish, distribute, sublicense, and/or sell copies of the Software,\n"
"and to permit persons to whom the Software is furnished to do so,\n"
"subject to the following conditions:\n"
"\n"
"The above copyright notice and this permission notice shall be\n"
"included in all copies or substantial portions of the Software.\n"
"\n"
"THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n"
"EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n"
"MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n"
"NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\n"
"BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n"
"ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n"
"CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n"
"SOFTWARE.\n"
;
void licence(void) {
fputs(licencemsg, stdout);
}
void version(void) {
#define SVN_REV "$Revision$"
char rev[sizeof(SVN_REV)];
char *p, *q;
strcpy(rev, SVN_REV);
for (p = rev; *p && *p != ':'; p++);
if (*p) {
p++;
while (*p && isspace(*p)) p++;
for (q = p; *q && *q != '$'; q++);
if (*q) *q = '\0';
printf("base64 revision %s\n", p);
} else {
printf("base64: unknown version\n");
}
}
int main(int ac, char **av) {
int encoding = 0;
int cpl = 64;
FILE *fp;
char *fname;
char *eptr;
fname = NULL;
while (--ac) {
char *v, *p = *++av;
if (*p == '-') {
while (*p) {
char c = *++p;
switch (c) {
case '-':
p++;
if (!strcmp(p, "version")) {
version();
exit(0);
} else if (!strcmp(p, "help")) {
usage();
exit(0);
} else if (!strcmp(p, "licence") ||
!strcmp(p, "license")) {
licence();
exit(0);
} else {
fprintf(stderr, "base64: unknown long option '--%s'\n",
p);
exit(1);
}
break;
case 'v':
case 'V':
version();
exit(0);
break;
case 'h':
case 'H':
usage();
exit(0);
break;
case 'd':
encoding = 0;
break;
case 'e':
encoding = 1;
break;
case 'c':
/*
* Options requiring values.
*/
v = p+1;
if (!*v && ac > 1) {
--ac;
v = *++av;
}
if (!*v) {
fprintf(stderr, "base64: option '-%c' expects"
" an argument\n", c);
exit(1);
}
switch (c) {
case 'c':
cpl = strtol(v, &eptr, 10);
if (eptr && *eptr) {
fprintf(stderr, "base64: option -c expects"
" a numeric argument\n");
exit(1);
}
if (cpl % 4) {
fprintf(stderr, "base64: chars per line should be"
" divisible by 4\n");
exit(1);
}
break;
}
p = "";
break;
}
}
} else {
if (!fname)
fname = p;
else {
fprintf(stderr, "base64: expected only one filename\n");
exit(0);
}
}
}
if (fname) {
fp = fopen(fname, encoding ? "rb" : "r");
if (!fp) {
fprintf(stderr, "base64: unable to open '%s': %s\n", fname,
strerror(errno));
exit(1);
}
} else
fp = stdin;
if (encoding) {
unsigned char in[3];
char out[4];
int column;
int n;
column = 0;
while (1) {
if (cpl && column >= cpl) {
putchar('\n');
column = 0;
}
n = fread(in, 1, 3, fp);
if (n == 0) break;
base64_encode_atom(in, n, out);
fwrite(out, 1, 4, stdout);
column += 4;
}
putchar('\n');
} else {
char in[4];
unsigned char out[3];
int c, i, n, eof;
eof = 0;
do {
for (i = 0; i < 4; i++) {
do {
c = fgetc(fp);
} while (c != EOF && !isbase64(c));
if (c == EOF) {
eof = 1;
break;
}
in[i] = c;
}
if (i > 0) {
if (i < 4) {
fprintf(stderr, "base64: warning: number of base64"
" characters was not a multiple of 4\n");
while (i < 4) in[i++] = '=';
}
n = base64_decode_atom(in, out);
fwrite(out, 1, n, stdout);
}
} while (!eof);
}
if (fname)
fclose(fp);
return 0;
}
# for `make release' and `make html'
DESTDIR = .
# for `make install'
PREFIX = /usr/local
BINDIR = $(PREFIX)/bin
SCRIPTDIR = $(PREFIX)/bin
MANDIR = $(PREFIX)/man/man1
INSTALL = install
IPROG =# flags for installing programs (default none)
IDATA = -m 0644 # flags for installing data
all: base64.1 base64
progs: base64
man: base64.1
base64: base64.c
$(CC) $(CFLAGS) -o $@ $<
%.1: %.but
halibut --man=$@ $<
clean:
rm -f *.1 base64 *.html *.tar.gz
html:
halibut --html=base64.html base64.but
mv base64.html $(DESTDIR)
release: base64.1
mkdir -p reltmp/base64
ln -s ../../base64.c reltmp/base64
ln -s ../../base64.1 reltmp/base64
ln -s ../../base64.but reltmp/base64
ln -s ../../Makefile reltmp/base64
tar -C reltmp -chzf $(DESTDIR)/base64.tar.gz base64
rm -rf reltmp
install: install-progs install-man
install-progs: base64
mkdir -p $(BINDIR)
$(INSTALL) $(IPROG) base64 $(BINDIR)/base64
install-man: base64.1
mkdir -p $(MANDIR)
$(INSTALL) $(IDATA) base64.1 $(MANDIR)/base64.1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment