/* Base64 encode/decode strings or files. This is the base64 utility
Copyright (C) 2004-2018 Free Software Foundation, Inc.
This file is part of Base64.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */ The GNUv3 license
/* Written by Simon Josefsson <simon@josefsson.org>. */
#include <config.h> Provides system specific information
#include <stdio.h> Provides standard I/O capability
#include <getopt.h> ...!includes auto-comment...
#include <sys/types.h> Provides system data types
#include "system.h" ...!includes auto-comment...
#include "die.h" ...!includes auto-comment...
#include "error.h" ...!includes auto-comment...
#include "fadvise.h" ...!includes auto-comment...
#include "quote.h" ...!includes auto-comment...
#include "xstrtol.h" ...!includes auto-comment...
#include "xdectoint.h" ...!includes auto-comment...
#include "xbinary-io.h" ...!includes auto-comment...
#define AUTHORS proper_name ("Simon Josefsson") Line 36
#if BASE_TYPE == 32 Line 38
# include "base32.h" Line 39
# define PROGRAM_NAME "base32" Line 40
#else Line 41
# include "base64.h" Line 42
# define PROGRAM_NAME "base64" Line 43
#endif Line 44
static struct option const long_options[] = Line 47
{
{"decode", no_argument, 0, 'd'}, Line 49
{"wrap", required_argument, 0, 'w'}, Line 50
{"ignore-garbage", no_argument, 0, 'i'}, Line 51
{GETOPT_HELP_OPTION_DECL}, Line 53
{GETOPT_VERSION_OPTION_DECL}, Line 54
{NULL, 0, NULL, 0} Line 55
}; Block 1
void Line 58
usage (int status) Line 59
{
if (status != EXIT_SUCCESS) Line 61
emit_try_help (); ...!common auto-comment...
else Line 63
{
printf (_("\ Line 65
Usage: %s [OPTION]... [FILE]\n\ Line 66
Base%d encode or decode FILE, or standard input, to standard output.\n\ Line 67
"), program_name, BASE_TYPE); Line 68
emit_stdin_note (); ...!common auto-comment...
emit_mandatory_arg_note (); ...!common auto-comment...
fputs (_("\ Line 73
-d, --decode decode data\n\ Line 74
-i, --ignore-garbage when decoding, ignore non-alphabet characters\n\ Line 75
-w, --wrap=COLS wrap encoded lines after COLS character (default 76).\n\Line 76
Use 0 to disable line wrapping\n\ Line 77
\n\
"), stdout); Line 79
fputs (HELP_OPTION_DESCRIPTION, stdout); Line 80
fputs (VERSION_OPTION_DESCRIPTION, stdout); Line 81
printf (_("\ Line 82
\n\
The data are encoded as described for the %s alphabet in RFC 4648.\n\ Line 84
When decoding, the input may contain newlines in addition to the bytes of\n\ Line 85
the formal %s alphabet. Use --ignore-garbage to attempt to recover\n\ Line 86
from any other non-alphabet bytes in the encoded stream.\n"), Line 87
PROGRAM_NAME, PROGRAM_NAME); Line 88
emit_ancillary_info (PROGRAM_NAME); Line 89
}
exit (status); Line 92
} Block 2
#define ENC_BLOCKSIZE (1024*3*10) Line 95
#if BASE_TYPE == 32 Line 97
# define BASE_LENGTH BASE32_LENGTH Line 98
/* Note that increasing this may decrease performance if --ignore-garbage
is used, because of the memmove operation below. */
# define DEC_BLOCKSIZE (1024*5) Line 101
/* Ensure that BLOCKSIZE is a multiple of 5 and 8. */
verify (ENC_BLOCKSIZE % 40 == 0); /* So padding chars only on last block. */ Line 104
verify (DEC_BLOCKSIZE % 40 == 0); /* So complete encoded blocks are used. */ Line 105
# define base_encode base32_encode Line 107
# define base_decode_context base32_decode_context Line 108
# define base_decode_ctx_init base32_decode_ctx_init Line 109
# define base_decode_ctx base32_decode_ctx Line 110
# define isbase isbase32 Line 111
#else Line 112
# define BASE_LENGTH BASE64_LENGTH Line 113
/* Note that increasing this may decrease performance if --ignore-garbage
is used, because of the memmove operation below. */
# define DEC_BLOCKSIZE (1024*3) Line 116
/* Ensure that BLOCKSIZE is a multiple of 3 and 4. */
verify (ENC_BLOCKSIZE % 12 == 0); /* So padding chars only on last block. */ Line 119
verify (DEC_BLOCKSIZE % 12 == 0); /* So complete encoded blocks are used. */ Line 120
# define base_encode base64_encode Line 122
# define base_decode_context base64_decode_context Line 123
# define base_decode_ctx_init base64_decode_ctx_init Line 124
# define base_decode_ctx base64_decode_ctx Line 125
# define isbase isbase64 Line 126
#endif Line 127
static void Line 129
wrap_write (const char *buffer, size_t len, Line 130...!syscalls auto-comment...
uintmax_t wrap_column, size_t *current_column, FILE *out) Line 131
{
size_t written; Line 133
if (wrap_column == 0) Line 135
{
/* Simple write. */
if (fwrite (buffer, 1, len, stdout) < len) Line 138...!syscalls auto-comment...
die (EXIT_FAILURE, errno, _("write error")); Line 139
}
else Line 141
for (written = 0; written < len;) Line 142
{
uintmax_t cols_remaining = wrap_column - *current_column; Line 144
size_t to_write = MIN (cols_remaining, SIZE_MAX); Line 145
to_write = MIN (to_write, len - written); Line 146
if (to_write == 0) Line 148
{
if (fputc ('\n', out) == EOF) Line 150
die (EXIT_FAILURE, errno, _("write error")); Line 151
*current_column = 0; Line 152
}
else Line 154
{
if (fwrite (buffer + written, 1, to_write, stdout) < to_write) Line 156...!syscalls auto-comment...
die (EXIT_FAILURE, errno, _("write error")); Line 157
*current_column += to_write; Line 158
written += to_write; Line 159
}
}
} Block 3
static void Line 164
do_encode (FILE *in, FILE *out, uintmax_t wrap_column) Line 165
{
size_t current_column = 0; Line 167
char inbuf[ENC_BLOCKSIZE]; Line 168
char outbuf[BASE_LENGTH (ENC_BLOCKSIZE)]; Line 169
size_t sum; Line 170
do
{
size_t n; Line 174
sum = 0; Line 176
do
{
n = fread (inbuf + sum, 1, ENC_BLOCKSIZE - sum, in); Line 179...!syscalls auto-comment...
sum += n; Line 180
}
while (!feof (in) && !ferror (in) && sum < ENC_BLOCKSIZE); Line 182
if (sum > 0) Line 184
{
/* Process input one block at a time. Note that ENC_BLOCKSIZE
is sized so that no pad chars will appear in output. */
base_encode (inbuf, sum, outbuf, BASE_LENGTH (sum)); Line 188
wrap_write (outbuf, BASE_LENGTH (sum), wrap_column, Line 190...!syscalls auto-comment...
¤t_column, out); Line 191
}
}
while (!feof (in) && !ferror (in) && sum == ENC_BLOCKSIZE); Line 194
/* When wrapping, terminate last line. */
if (wrap_column && current_column > 0 && fputc ('\n', out) == EOF) Line 197
die (EXIT_FAILURE, errno, _("write error")); Line 198
if (ferror (in)) Line 200
die (EXIT_FAILURE, errno, _("read error")); Line 201
} Block 4
static void Line 204
do_decode (FILE *in, FILE *out, bool ignore_garbage) Line 205
{
char inbuf[BASE_LENGTH (DEC_BLOCKSIZE)]; Line 207
char outbuf[DEC_BLOCKSIZE]; Line 208
size_t sum; Line 209
struct base_decode_context ctx; Line 210
base_decode_ctx_init (&ctx); Line 212
do
{
bool ok; Line 216
size_t n; Line 217
unsigned int k; Line 218
sum = 0; Line 220
do
{
n = fread (inbuf + sum, 1, BASE_LENGTH (DEC_BLOCKSIZE) - sum, in); Line 223...!syscalls auto-comment...
if (ignore_garbage) Line 225
{
for (size_t i = 0; n > 0 && i < n;) Line 227
{
if (isbase (inbuf[sum + i]) || inbuf[sum + i] == '=') Line 229
i++; Line 230
else Line 231
memmove (inbuf + sum + i, inbuf + sum + i + 1, --n - i); Line 232
}
}
sum += n; Line 236
if (ferror (in)) Line 238
die (EXIT_FAILURE, errno, _("read error")); Line 239
}
while (sum < BASE_LENGTH (DEC_BLOCKSIZE) && !feof (in)); Line 241
/* The following "loop" is usually iterated just once.
However, when it processes the final input buffer, we want
to iterate it one additional time, but with an indicator
telling it to flush what is in CTX. */
for (k = 0; k < 1 + !!feof (in); k++) Line 247
{
if (k == 1 && ctx.i == 0) Line 249
break; Line 250
n = DEC_BLOCKSIZE; Line 251
ok = base_decode_ctx (&ctx, inbuf, (k == 0 ? sum : 0), outbuf, &n); Line 252
if (fwrite (outbuf, 1, n, out) < n) Line 254...!syscalls auto-comment...
die (EXIT_FAILURE, errno, _("write error")); Line 255
if (!ok) Line 257
die (EXIT_FAILURE, 0, _("invalid input")); Line 258
}
}
while (!feof (in)); Line 261
} Block 5
int
main (int argc, char **argv) Line 265
{
int opt; Line 267
FILE *input_fh; Line 268
const char *infile; Line 269
/* True if --decode has been given and we should decode data. */
bool decode = false; Line 272
/* True if we should ignore non-base-alphabetic characters. */
bool ignore_garbage = false; Line 274
/* Wrap encoded data around the 76:th column, by default. */
uintmax_t wrap_column = 76; Line 276
initialize_main (&argc, &argv); VMS-specific entry point handling wildcard expansion
set_program_name (argv[0]); Retains program name and discards path
setlocale (LC_ALL, ""); Sets up internationalization (i18n)
bindtextdomain (PACKAGE, LOCALEDIR); Assigns i18n directorySets text domain for _() [gettext()] function
textdomain (PACKAGE); Sets text domain for _() [gettext()] function
atexit (close_stdout); Close stdout on exit (see gnulib)
while ((opt = getopt_long (argc, argv, "diw:", long_options, NULL)) != -1) Line 286
switch (opt) Line 287
{
case 'd': Line 289
decode = true; Line 290
break; Line 291
case 'w': Line 293
wrap_column = xdectoumax (optarg, 0, UINTMAX_MAX, "", Line 294
_("invalid wrap size"), 0); Line 295
break; Line 296
case 'i': Line 298
ignore_garbage = true; Line 299
break; Line 300
case_GETOPT_HELP_CHAR; Line 302
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); Line 304
default: Line 306
usage (EXIT_FAILURE); Line 307
break; Line 308
}
if (argc - optind > 1) Line 311
{
error (0, 0, _("extra operand %s"), quote (argv[optind])); Line 313
usage (EXIT_FAILURE); Line 314
}
if (optind < argc) Line 317
infile = argv[optind]; Line 318
else Line 319
infile = "-"; Line 320
if (STREQ (infile, "-")) Line 322
{
xset_binary_mode (STDIN_FILENO, O_BINARY); Line 324
input_fh = stdin; Line 325
}
else Line 327
{
input_fh = fopen (infile, "rb"); Line 329...!syscalls auto-comment...
if (input_fh == NULL) Line 330
die (EXIT_FAILURE, errno, "%s", quotef (infile)); Line 331
}
fadvise (input_fh, FADVISE_SEQUENTIAL); Line 334...!syscalls auto-comment...
if (decode) Line 336
do_decode (input_fh, stdout, ignore_garbage); Line 337
else Line 338
do_encode (input_fh, stdout, wrap_column); Line 339
if (fclose (input_fh) == EOF) Line 341...!syscalls auto-comment...
{
if (STREQ (infile, "-")) Line 343
die (EXIT_FAILURE, errno, _("closing standard input")); Line 344
else Line 345
die (EXIT_FAILURE, errno, "%s", quotef (infile)); Line 346
}
return EXIT_SUCCESS; Line 349
} Block 6