tests: cleanup trapping of signal names
[coreutils.git] / src / base64.c
blob5ec9a9e0abde79a61e015730a20867b86698bab9
1 /* Base64 encode/decode strings or files.
2 Copyright (C) 2004-2015 Free Software Foundation, Inc.
4 This file is part of Base64.
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 /* Written by Simon Josefsson <simon@josefsson.org>. */
21 #include <config.h>
23 #include <stdio.h>
24 #include <getopt.h>
25 #include <sys/types.h>
27 #include "system.h"
28 #include "error.h"
29 #include "fadvise.h"
30 #include "quote.h"
31 #include "xstrtol.h"
32 #include "xdectoint.h"
33 #include "xfreopen.h"
35 #define AUTHORS proper_name ("Simon Josefsson")
37 #if BASE_TYPE == 32
38 # include "base32.h"
39 # define PROGRAM_NAME "base32"
40 #else
41 # include "base64.h"
42 # define PROGRAM_NAME "base64"
43 #endif
46 static struct option const long_options[] =
48 {"decode", no_argument, 0, 'd'},
49 {"wrap", required_argument, 0, 'w'},
50 {"ignore-garbage", no_argument, 0, 'i'},
52 {GETOPT_HELP_OPTION_DECL},
53 {GETOPT_VERSION_OPTION_DECL},
54 {NULL, 0, NULL, 0}
57 void
58 usage (int status)
60 if (status != EXIT_SUCCESS)
61 emit_try_help ();
62 else
64 printf (_("\
65 Usage: %s [OPTION]... [FILE]\n\
66 Base%d encode or decode FILE, or standard input, to standard output.\n\
67 "), program_name, BASE_TYPE);
69 emit_stdin_note ();
70 emit_mandatory_arg_note ();
72 fputs (_("\
73 -d, --decode decode data\n\
74 -i, --ignore-garbage when decoding, ignore non-alphabet characters\n\
75 -w, --wrap=COLS wrap encoded lines after COLS character (default 76).\n\
76 Use 0 to disable line wrapping\n\
77 \n\
78 "), stdout);
79 fputs (HELP_OPTION_DESCRIPTION, stdout);
80 fputs (VERSION_OPTION_DESCRIPTION, stdout);
81 printf (_("\
82 \n\
83 The data are encoded as described for the %s alphabet in RFC 4648.\n\
84 When decoding, the input may contain newlines in addition to the bytes of\n\
85 the formal %s alphabet. Use --ignore-garbage to attempt to recover\n\
86 from any other non-alphabet bytes in the encoded stream.\n"),
87 PROGRAM_NAME, PROGRAM_NAME);
88 emit_ancillary_info (PROGRAM_NAME);
91 exit (status);
94 #define ENC_BLOCKSIZE (1024*3*10)
96 #if BASE_TYPE == 32
97 # define BASE_LENGTH BASE32_LENGTH
98 /* Note that increasing this may decrease performance if --ignore-garbage
99 is used, because of the memmove operation below. */
100 # define DEC_BLOCKSIZE (1024*5)
102 /* Ensure that BLOCKSIZE is a multiple of 5 and 8. */
103 verify (ENC_BLOCKSIZE % 40 == 0); /* So padding chars only on last block. */
104 verify (DEC_BLOCKSIZE % 40 == 0); /* So complete encoded blocks are used. */
106 # define base_encode base32_encode
107 # define base_decode_context base32_decode_context
108 # define base_decode_ctx_init base32_decode_ctx_init
109 # define base_decode_ctx base32_decode_ctx
110 # define isbase isbase32
111 #else
112 # define BASE_LENGTH BASE64_LENGTH
113 /* Note that increasing this may decrease performance if --ignore-garbage
114 is used, because of the memmove operation below. */
115 # define DEC_BLOCKSIZE (1024*3)
117 /* Ensure that BLOCKSIZE is a multiple of 3 and 4. */
118 verify (ENC_BLOCKSIZE % 12 == 0); /* So padding chars only on last block. */
119 verify (DEC_BLOCKSIZE % 12 == 0); /* So complete encoded blocks are used. */
121 # define base_encode base64_encode
122 # define base_decode_context base64_decode_context
123 # define base_decode_ctx_init base64_decode_ctx_init
124 # define base_decode_ctx base64_decode_ctx
125 # define isbase isbase64
126 #endif
128 static void
129 wrap_write (const char *buffer, size_t len,
130 uintmax_t wrap_column, size_t *current_column, FILE *out)
132 size_t written;
134 if (wrap_column == 0)
136 /* Simple write. */
137 if (fwrite (buffer, 1, len, stdout) < len)
138 error (EXIT_FAILURE, errno, _("write error"));
140 else
141 for (written = 0; written < len;)
143 uintmax_t cols_remaining = wrap_column - *current_column;
144 size_t to_write = MIN (cols_remaining, SIZE_MAX);
145 to_write = MIN (to_write, len - written);
147 if (to_write == 0)
149 if (fputc ('\n', out) == EOF)
150 error (EXIT_FAILURE, errno, _("write error"));
151 *current_column = 0;
153 else
155 if (fwrite (buffer + written, 1, to_write, stdout) < to_write)
156 error (EXIT_FAILURE, errno, _("write error"));
157 *current_column += to_write;
158 written += to_write;
163 static void
164 do_encode (FILE *in, FILE *out, uintmax_t wrap_column)
166 size_t current_column = 0;
167 char inbuf[ENC_BLOCKSIZE];
168 char outbuf[BASE_LENGTH (ENC_BLOCKSIZE)];
169 size_t sum;
173 size_t n;
175 sum = 0;
178 n = fread (inbuf + sum, 1, ENC_BLOCKSIZE - sum, in);
179 sum += n;
181 while (!feof (in) && !ferror (in) && sum < ENC_BLOCKSIZE);
183 if (sum > 0)
185 /* Process input one block at a time. Note that ENC_BLOCKSIZE
186 is sized so that no pad chars will appear in output. */
187 base_encode (inbuf, sum, outbuf, BASE_LENGTH (sum));
189 wrap_write (outbuf, BASE_LENGTH (sum), wrap_column,
190 &current_column, out);
193 while (!feof (in) && !ferror (in) && sum == ENC_BLOCKSIZE);
195 /* When wrapping, terminate last line. */
196 if (wrap_column && current_column > 0 && fputc ('\n', out) == EOF)
197 error (EXIT_FAILURE, errno, _("write error"));
199 if (ferror (in))
200 error (EXIT_FAILURE, errno, _("read error"));
203 static void
204 do_decode (FILE *in, FILE *out, bool ignore_garbage)
206 char inbuf[BASE_LENGTH (DEC_BLOCKSIZE)];
207 char outbuf[DEC_BLOCKSIZE];
208 size_t sum;
209 struct base_decode_context ctx;
211 base_decode_ctx_init (&ctx);
215 bool ok;
216 size_t n;
217 unsigned int k;
219 sum = 0;
222 n = fread (inbuf + sum, 1, BASE_LENGTH (DEC_BLOCKSIZE) - sum, in);
224 if (ignore_garbage)
226 size_t i;
227 for (i = 0; n > 0 && i < n;)
228 if (isbase (inbuf[sum + i]) || inbuf[sum + i] == '=')
229 i++;
230 else
231 memmove (inbuf + sum + i, inbuf + sum + i + 1, --n - i);
234 sum += n;
236 if (ferror (in))
237 error (EXIT_FAILURE, errno, _("read error"));
239 while (sum < BASE_LENGTH (DEC_BLOCKSIZE) && !feof (in));
241 /* The following "loop" is usually iterated just once.
242 However, when it processes the final input buffer, we want
243 to iterate it one additional time, but with an indicator
244 telling it to flush what is in CTX. */
245 for (k = 0; k < 1 + !!feof (in); k++)
247 if (k == 1 && ctx.i == 0)
248 break;
249 n = DEC_BLOCKSIZE;
250 ok = base_decode_ctx (&ctx, inbuf, (k == 0 ? sum : 0), outbuf, &n);
252 if (fwrite (outbuf, 1, n, out) < n)
253 error (EXIT_FAILURE, errno, _("write error"));
255 if (!ok)
256 error (EXIT_FAILURE, 0, _("invalid input"));
259 while (!feof (in));
263 main (int argc, char **argv)
265 int opt;
266 FILE *input_fh;
267 const char *infile;
269 /* True if --decode has been given and we should decode data. */
270 bool decode = false;
271 /* True if we should ignore non-base-alphabetic characters. */
272 bool ignore_garbage = false;
273 /* Wrap encoded data around the 76:th column, by default. */
274 uintmax_t wrap_column = 76;
276 initialize_main (&argc, &argv);
277 set_program_name (argv[0]);
278 setlocale (LC_ALL, "");
279 bindtextdomain (PACKAGE, LOCALEDIR);
280 textdomain (PACKAGE);
282 atexit (close_stdout);
284 while ((opt = getopt_long (argc, argv, "diw:", long_options, NULL)) != -1)
285 switch (opt)
287 case 'd':
288 decode = true;
289 break;
291 case 'w':
292 wrap_column = xdectoumax (optarg, 0, UINTMAX_MAX, "",
293 _("invalid wrap size"), 0);
294 break;
296 case 'i':
297 ignore_garbage = true;
298 break;
300 case_GETOPT_HELP_CHAR;
302 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
304 default:
305 usage (EXIT_FAILURE);
306 break;
309 if (argc - optind > 1)
311 error (0, 0, _("extra operand %s"), quote (argv[optind]));
312 usage (EXIT_FAILURE);
315 if (optind < argc)
316 infile = argv[optind];
317 else
318 infile = "-";
320 if (STREQ (infile, "-"))
322 if (O_BINARY)
323 xfreopen (NULL, "rb", stdin);
324 input_fh = stdin;
326 else
328 input_fh = fopen (infile, "rb");
329 if (input_fh == NULL)
330 error (EXIT_FAILURE, errno, "%s", quotef (infile));
333 fadvise (input_fh, FADVISE_SEQUENTIAL);
335 if (decode)
336 do_decode (input_fh, stdout, ignore_garbage);
337 else
338 do_encode (input_fh, stdout, wrap_column);
340 if (fclose (input_fh) == EOF)
342 if (STREQ (infile, "-"))
343 error (EXIT_FAILURE, errno, _("closing standard input"));
344 else
345 error (EXIT_FAILURE, errno, "%s", quotef (infile));
348 return EXIT_SUCCESS;