summaryrefslogtreecommitdiff
path: root/src/base64.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/base64.c')
-rw-r--r--src/base64.c329
1 files changed, 178 insertions, 151 deletions
diff --git a/src/base64.c b/src/base64.c
index 9f8ff41..83f0e9d 100644
--- a/src/base64.c
+++ b/src/base64.c
@@ -1,22 +1,20 @@
/* Base64 encode/decode strings or files.
- Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+ Copyright (C) 2004-2016 Free Software Foundation, Inc.
This file is part of Base64.
- Base64 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 2, or (at your option)
- any later version.
+ 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.
- Base64 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.
+ 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 Base64; see the file COPYING. If not, write to the Free
- Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- MA 02110-1301, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* Written by Simon Josefsson <simon@josefsson.org>. */
@@ -28,84 +26,108 @@
#include "system.h"
#include "error.h"
-#include "xstrtol.h"
+#include "fadvise.h"
#include "quote.h"
-#include "quotearg.h"
-
-#include "base64.h"
+#include "xstrtol.h"
+#include "xdectoint.h"
+#include "xfreopen.h"
-/* The official name of this program (e.g., no `g' prefix). */
-#define PROGRAM_NAME "base64"
+#define AUTHORS proper_name ("Simon Josefsson")
-#define AUTHOR "Simon Josefsson"
+#if BASE_TYPE == 32
+# include "base32.h"
+# define PROGRAM_NAME "base32"
+#else
+# include "base64.h"
+# define PROGRAM_NAME "base64"
+#endif
-/* The invocation name of this program. */
-char *program_name;
-static const struct option long_options[] = {
+static struct option const long_options[] =
+{
{"decode", no_argument, 0, 'd'},
{"wrap", required_argument, 0, 'w'},
{"ignore-garbage", no_argument, 0, 'i'},
- {"help", no_argument, 0, GETOPT_HELP_CHAR},
- {"version", no_argument, 0, GETOPT_VERSION_CHAR},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
};
-static void
+void
usage (int status)
{
if (status != EXIT_SUCCESS)
- fprintf (stderr, _("Try `%s --help' for more information.\n"),
- program_name);
+ emit_try_help ();
else
{
printf (_("\
-Usage: %s [OPTION] [FILE]\n\
-Base64 encode or decode FILE, or standard input, to standard output.\n\
-\n"), program_name);
+Usage: %s [OPTION]... [FILE]\n\
+Base%d encode or decode FILE, or standard input, to standard output.\n\
+"), program_name, BASE_TYPE);
+
+ emit_stdin_note ();
+ emit_mandatory_arg_note ();
+
fputs (_("\
- -w, --wrap=COLS Wrap encoded lines after COLS character (default 76).\n\
- Use 0 to disable line wrapping.\n\
-\n\
- -d, --decode Decode data.\n\
- -i, --ignore-garbage When decoding, ignore non-alphabet characters.\n\
+ -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\
\n\
"), stdout);
- fputs (_("\
- --help Display this help and exit.\n\
- --version Output version information and exit.\n"), stdout);
- fputs (_("\
-\n\
-With no FILE, or when FILE is -, read standard input.\n"), stdout);
- fputs (_("\
+ fputs (HELP_OPTION_DESCRIPTION, stdout);
+ fputs (VERSION_OPTION_DESCRIPTION, stdout);
+ printf (_("\
\n\
-The data are encoded as described for the base64 alphabet in RFC 3548.\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 base64 alphabet. Use --ignore-garbage to attempt to recover\n\
+the formal %s alphabet. Use --ignore-garbage to attempt to recover\n\
from any other non-alphabet bytes in the encoded stream.\n"),
- stdout);
- printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
+ PROGRAM_NAME, PROGRAM_NAME);
+ emit_ancillary_info (PROGRAM_NAME);
}
exit (status);
}
+#define ENC_BLOCKSIZE (1024*3*10)
+
+#if BASE_TYPE == 32
+# define BASE_LENGTH BASE32_LENGTH
/* Note that increasing this may decrease performance if --ignore-garbage
- is used, because of the memmove operation below. */
-#define BLOCKSIZE 3072
-#define B64BLOCKSIZE BASE64_LENGTH (BLOCKSIZE)
+ is used, because of the memmove operation below. */
+# define DEC_BLOCKSIZE (1024*5)
+
+/* Ensure that BLOCKSIZE is a multiple of 5 and 8. */
+verify (ENC_BLOCKSIZE % 40 == 0); /* So padding chars only on last block. */
+verify (DEC_BLOCKSIZE % 40 == 0); /* So complete encoded blocks are used. */
+
+# 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 isbase isbase32
+#else
+# define BASE_LENGTH BASE64_LENGTH
+/* Note that increasing this may decrease performance if --ignore-garbage
+ is used, because of the memmove operation below. */
+# define DEC_BLOCKSIZE (1024*3)
/* Ensure that BLOCKSIZE is a multiple of 3 and 4. */
-#if BLOCKSIZE % 12 != 0
-# error "invalid BLOCKSIZE"
+verify (ENC_BLOCKSIZE % 12 == 0); /* So padding chars only on last block. */
+verify (DEC_BLOCKSIZE % 12 == 0); /* So complete encoded blocks are used. */
+
+# 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 isbase isbase64
#endif
static void
wrap_write (const char *buffer, size_t len,
- uintmax_t wrap_column, size_t *current_column, FILE *out)
+ uintmax_t wrap_column, size_t *current_column, FILE *out)
{
size_t written;
@@ -113,28 +135,28 @@ wrap_write (const char *buffer, size_t len,
{
/* Simple write. */
if (fwrite (buffer, 1, len, stdout) < len)
- error (EXIT_FAILURE, errno, _("write error"));
+ error (EXIT_FAILURE, errno, _("write error"));
}
else
for (written = 0; written < len;)
{
- uintmax_t cols_remaining = wrap_column - *current_column;
- size_t to_write = MIN (cols_remaining, SIZE_MAX);
- to_write = MIN (to_write, len - written);
-
- if (to_write == 0)
- {
- if (fputs ("\n", out) < 0)
- error (EXIT_FAILURE, errno, _("write error"));
- *current_column = 0;
- }
- else
- {
- if (fwrite (buffer + written, 1, to_write, stdout) < to_write)
- error (EXIT_FAILURE, errno, _("write error"));
- *current_column += to_write;
- written += to_write;
- }
+ uintmax_t cols_remaining = wrap_column - *current_column;
+ size_t to_write = MIN (cols_remaining, SIZE_MAX);
+ to_write = MIN (to_write, len - written);
+
+ if (to_write == 0)
+ {
+ if (fputc ('\n', out) == EOF)
+ error (EXIT_FAILURE, errno, _("write error"));
+ *current_column = 0;
+ }
+ else
+ {
+ if (fwrite (buffer + written, 1, to_write, stdout) < to_write)
+ error (EXIT_FAILURE, errno, _("write error"));
+ *current_column += to_write;
+ written += to_write;
+ }
}
}
@@ -142,8 +164,8 @@ static void
do_encode (FILE *in, FILE *out, uintmax_t wrap_column)
{
size_t current_column = 0;
- char inbuf[BLOCKSIZE];
- char outbuf[B64BLOCKSIZE];
+ char inbuf[ENC_BLOCKSIZE];
+ char outbuf[BASE_LENGTH (ENC_BLOCKSIZE)];
size_t sum;
do
@@ -152,26 +174,26 @@ do_encode (FILE *in, FILE *out, uintmax_t wrap_column)
sum = 0;
do
- {
- n = fread (inbuf + sum, 1, BLOCKSIZE - sum, in);
- sum += n;
- }
- while (!feof (in) && !ferror (in) && sum < BLOCKSIZE);
+ {
+ n = fread (inbuf + sum, 1, ENC_BLOCKSIZE - sum, in);
+ sum += n;
+ }
+ while (!feof (in) && !ferror (in) && sum < ENC_BLOCKSIZE);
if (sum > 0)
- {
- /* Process input one block at a time. Note that BLOCKSIZE %
- 3 == 0, so that no base64 pads will appear in output. */
- base64_encode (inbuf, sum, outbuf, BASE64_LENGTH (sum));
-
- wrap_write (outbuf, BASE64_LENGTH (sum), wrap_column,
- &current_column, out);
- }
+ {
+ /* 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));
+
+ wrap_write (outbuf, BASE_LENGTH (sum), wrap_column,
+ &current_column, out);
+ }
}
- while (!feof (in) && !ferror (in) && sum == BLOCKSIZE);
+ while (!feof (in) && !ferror (in) && sum == ENC_BLOCKSIZE);
/* When wrapping, terminate last line. */
- if (wrap_column && current_column > 0 && fputs ("\n", out) < 0)
+ if (wrap_column && current_column > 0 && fputc ('\n', out) == EOF)
error (EXIT_FAILURE, errno, _("write error"));
if (ferror (in))
@@ -181,12 +203,12 @@ do_encode (FILE *in, FILE *out, uintmax_t wrap_column)
static void
do_decode (FILE *in, FILE *out, bool ignore_garbage)
{
- char inbuf[B64BLOCKSIZE];
- char outbuf[BLOCKSIZE];
+ char inbuf[BASE_LENGTH (DEC_BLOCKSIZE)];
+ char outbuf[DEC_BLOCKSIZE];
size_t sum;
- struct base64_decode_context ctx;
+ struct base_decode_context ctx;
- base64_decode_ctx_init (&ctx);
+ base_decode_ctx_init (&ctx);
do
{
@@ -196,43 +218,43 @@ do_decode (FILE *in, FILE *out, bool ignore_garbage)
sum = 0;
do
- {
- n = fread (inbuf + sum, 1, B64BLOCKSIZE - sum, in);
-
- if (ignore_garbage)
- {
- size_t i;
- for (i = 0; n > 0 && i < n;)
- if (isbase64 (inbuf[sum + i]) || 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 < B64BLOCKSIZE && !feof (in));
+ {
+ n = fread (inbuf + sum, 1, BASE_LENGTH (DEC_BLOCKSIZE) - sum, in);
+
+ if (ignore_garbage)
+ {
+ size_t i;
+ for (i = 0; n > 0 && i < n;)
+ if (isbase (inbuf[sum + i]) || 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));
/* 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++)
- {
- if (k == 1 && ctx.i == 0)
- break;
- n = BLOCKSIZE;
- ok = base64_decode (&ctx, inbuf, (k == 0 ? sum : 0), outbuf, &n);
-
- if (fwrite (outbuf, 1, n, out) < n)
- error (EXIT_FAILURE, errno, _("write error"));
-
- if (!ok)
- error (EXIT_FAILURE, 0, _("invalid input"));
- }
+ 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++)
+ {
+ if (k == 1 && ctx.i == 0)
+ break;
+ n = DEC_BLOCKSIZE;
+ ok = base_decode_ctx (&ctx, inbuf, (k == 0 ? sum : 0), outbuf, &n);
+
+ if (fwrite (outbuf, 1, n, out) < n)
+ error (EXIT_FAILURE, errno, _("write error"));
+
+ if (!ok)
+ error (EXIT_FAILURE, 0, _("invalid input"));
+ }
}
while (!feof (in));
}
@@ -244,45 +266,44 @@ main (int argc, char **argv)
FILE *input_fh;
const char *infile;
- /* True if --decode has bene given and we should decode data. */
+ /* True if --decode has been given and we should decode data. */
bool decode = false;
- /* True if we should ignore non-alphabetic characters. */
+ /* True if we should ignore non-base-alphabetic characters. */
bool ignore_garbage = false;
- /* Wrap encoded base64 data around the 76:th column, by default. */
+ /* Wrap encoded data around the 76:th column, by default. */
uintmax_t wrap_column = 76;
initialize_main (&argc, &argv);
- program_name = argv[0];
+ set_program_name (argv[0]);
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
- while ((opt = getopt_long (argc, argv, "dqiw:", long_options, NULL)) != -1)
+ while ((opt = getopt_long (argc, argv, "diw:", long_options, NULL)) != -1)
switch (opt)
{
case 'd':
- decode = true;
- break;
+ decode = true;
+ break;
case 'w':
- if (xstrtoumax (optarg, NULL, 0, &wrap_column, NULL) != LONGINT_OK)
- error (EXIT_FAILURE, 0, _("invalid wrap size: %s"),
- quotearg (optarg));
- break;
+ wrap_column = xdectoumax (optarg, 0, UINTMAX_MAX, "",
+ _("invalid wrap size"), 0);
+ break;
case 'i':
- ignore_garbage = true;
- break;
+ ignore_garbage = true;
+ break;
- case_GETOPT_HELP_CHAR;
+ case_GETOPT_HELP_CHAR;
- case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHOR);
+ case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
- usage (EXIT_FAILURE);
- break;
+ usage (EXIT_FAILURE);
+ break;
}
if (argc - optind > 1)
@@ -296,15 +317,21 @@ main (int argc, char **argv)
else
infile = "-";
- if (strcmp (infile, "-") == 0)
- input_fh = stdin;
+ if (STREQ (infile, "-"))
+ {
+ if (O_BINARY)
+ xfreopen (NULL, "rb", stdin);
+ input_fh = stdin;
+ }
else
{
- input_fh = fopen (infile, "r");
+ input_fh = fopen (infile, "rb");
if (input_fh == NULL)
- error (EXIT_FAILURE, errno, "%s", infile);
+ error (EXIT_FAILURE, errno, "%s", quotef (infile));
}
+ fadvise (input_fh, FADVISE_SEQUENTIAL);
+
if (decode)
do_decode (input_fh, stdout, ignore_garbage);
else
@@ -312,11 +339,11 @@ main (int argc, char **argv)
if (fclose (input_fh) == EOF)
{
- if (strcmp (infile, "-") == 0)
- error (EXIT_FAILURE, errno, _("closing standard input"));
+ if (STREQ (infile, "-"))
+ error (EXIT_FAILURE, errno, _("closing standard input"));
else
- error (EXIT_FAILURE, errno, "%s", infile);
+ error (EXIT_FAILURE, errno, "%s", quotef (infile));
}
- exit (EXIT_SUCCESS);
+ return EXIT_SUCCESS;
}