1 /* Base64 encode/decode strings or files.
2 Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
4 This file is part of Base64.
6 Base64 is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 Base64 is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with Base64; see the file COPYING. If not, write to the Free
18 Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 MA 02110-1301, USA. */
21 /* Written by Simon Josefsson <simon@josefsson.org>. */
27 #include <sys/types.h>
37 /* The official name of this program (e.g., no `g' prefix). */
38 #define PROGRAM_NAME "base64"
40 #define AUTHOR "Simon Josefsson"
42 /* The invocation name of this program. */
45 static const struct option long_options[] = {
46 {"decode", no_argument, 0, 'd'},
47 {"wrap", required_argument, 0, 'w'},
48 {"ignore-garbage", no_argument, 0, 'i'},
49 {"help", no_argument, 0, GETOPT_HELP_CHAR},
50 {"version", no_argument, 0, GETOPT_VERSION_CHAR},
52 {GETOPT_HELP_OPTION_DECL},
53 {GETOPT_VERSION_OPTION_DECL},
60 if (status != EXIT_SUCCESS)
61 fprintf (stderr, _("Try `%s --help' for more information.\n"),
66 Usage: %s [OPTION] [FILE]\n\
67 Base64 encode or decode FILE, or standard input, to standard output.\n\
70 -w, --wrap=COLS Wrap encoded lines after COLS character (default 76).\n\
71 Use 0 to disable line wrapping.\n\
73 -d, --decode Decode data.\n\
74 -i, --ignore-garbage When decoding, ignore non-alphabet characters.\n\
78 --help Display this help and exit.\n\
79 --version Output version information and exit.\n"), stdout);
82 With no FILE, or when FILE is -, read standard input.\n"), stdout);
85 The data are encoded as described for the base64 alphabet in RFC 3548.\n\
86 When decoding, the input may contain newlines in addition to the bytes of\n\
87 the formal base64 alphabet. Use --ignore-garbage to attempt to recover\n\
88 from any other non-alphabet bytes in the encoded stream.\n"),
90 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
96 /* Note that increasing this may decrease performance if --ignore-garbage
97 is used, because of the memmove operation below. */
98 #define BLOCKSIZE 3072
99 #define B64BLOCKSIZE BASE64_LENGTH (BLOCKSIZE)
101 /* Ensure that BLOCKSIZE is a multiple of 3 and 4. */
102 #if BLOCKSIZE % 12 != 0
103 # error "invalid BLOCKSIZE"
107 wrap_write (const char *buffer, size_t len,
108 uintmax_t wrap_column, size_t *current_column, FILE *out)
112 if (wrap_column == 0)
115 if (fwrite (buffer, 1, len, stdout) < len)
116 error (EXIT_FAILURE, errno, _("write error"));
119 for (written = 0; written < len;)
121 uintmax_t cols_remaining = wrap_column - *current_column;
122 size_t to_write = MIN (cols_remaining, SIZE_MAX);
123 to_write = MIN (to_write, len - written);
127 if (fputs ("\n", out) < 0)
128 error (EXIT_FAILURE, errno, _("write error"));
133 if (fwrite (buffer + written, 1, to_write, stdout) < to_write)
134 error (EXIT_FAILURE, errno, _("write error"));
135 *current_column += to_write;
142 do_encode (FILE *in, FILE *out, uintmax_t wrap_column)
144 size_t current_column = 0;
145 char inbuf[BLOCKSIZE];
146 char outbuf[B64BLOCKSIZE];
156 n = fread (inbuf + sum, 1, BLOCKSIZE - sum, in);
159 while (!feof (in) && !ferror (in) && sum < BLOCKSIZE);
163 /* Process input one block at a time. Note that BLOCKSIZE %
164 3 == 0, so that no base64 pads will appear in output. */
165 base64_encode (inbuf, sum, outbuf, BASE64_LENGTH (sum));
167 wrap_write (outbuf, BASE64_LENGTH (sum), wrap_column,
168 ¤t_column, out);
171 while (!feof (in) && !ferror (in) && sum == BLOCKSIZE);
173 /* When wrapping, terminate last line. */
174 if (wrap_column && current_column > 0 && fputs ("\n", out) < 0)
175 error (EXIT_FAILURE, errno, _("write error"));
178 error (EXIT_FAILURE, errno, _("read error"));
182 do_decode (FILE *in, FILE *out, bool ignore_garbage)
184 char inbuf[B64BLOCKSIZE];
185 char outbuf[BLOCKSIZE];
187 struct base64_decode_context ctx;
189 base64_decode_ctx_init (&ctx);
200 n = fread (inbuf + sum, 1, B64BLOCKSIZE - sum, in);
205 for (i = 0; n > 0 && i < n;)
206 if (isbase64 (inbuf[sum + i]) || inbuf[sum + i] == '=')
209 memmove (inbuf + sum + i, inbuf + sum + i + 1, --n - i);
215 error (EXIT_FAILURE, errno, _("read error"));
217 while (sum < B64BLOCKSIZE && !feof (in));
219 /* The following "loop" is usually iterated just once.
220 However, when it processes the final input buffer, we want
221 to iterate it one additional time, but with an indicator
222 telling it to flush what is in CTX. */
223 for (k = 0; k < 1 + feof (in); k++)
225 if (k == 1 && ctx.i == 0)
228 ok = base64_decode (&ctx, inbuf, (k == 0 ? sum : 0), outbuf, &n);
230 if (fwrite (outbuf, 1, n, out) < n)
231 error (EXIT_FAILURE, errno, _("write error"));
234 error (EXIT_FAILURE, 0, _("invalid input"));
241 main (int argc, char **argv)
247 /* True if --decode has bene given and we should decode data. */
249 /* True if we should ignore non-alphabetic characters. */
250 bool ignore_garbage = false;
251 /* Wrap encoded base64 data around the 76:th column, by default. */
252 uintmax_t wrap_column = 76;
254 initialize_main (&argc, &argv);
255 program_name = argv[0];
256 setlocale (LC_ALL, "");
257 bindtextdomain (PACKAGE, LOCALEDIR);
258 textdomain (PACKAGE);
260 atexit (close_stdout);
262 while ((opt = getopt_long (argc, argv, "dqiw:", long_options, NULL)) != -1)
270 if (xstrtoumax (optarg, NULL, 0, &wrap_column, NULL) != LONGINT_OK)
271 error (EXIT_FAILURE, 0, _("invalid wrap size: %s"),
276 ignore_garbage = true;
279 case_GETOPT_HELP_CHAR;
281 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHOR);
284 usage (EXIT_FAILURE);
288 if (argc - optind > 1)
290 error (0, 0, _("extra operand %s"), quote (argv[optind]));
291 usage (EXIT_FAILURE);
295 infile = argv[optind];
299 if (strcmp (infile, "-") == 0)
303 input_fh = fopen (infile, "r");
304 if (input_fh == NULL)
305 error (EXIT_FAILURE, errno, "%s", infile);
309 do_decode (input_fh, stdout, ignore_garbage);
311 do_encode (input_fh, stdout, wrap_column);
313 if (fclose (input_fh) == EOF)
315 if (strcmp (infile, "-") == 0)
316 error (EXIT_FAILURE, errno, _("closing standard input"));
318 error (EXIT_FAILURE, errno, "%s", infile);