ptx: fix an invalid heap reference with short --width
[coreutils.git] / src / base64.c
blob0bb8b44db3df4bdf52695c552e114092b42ab282
1 /* Base64 encode/decode strings or files.
2 Copyright (C) 2004-2016 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 "die.h"
29 #include "error.h"
30 #include "fadvise.h"
31 #include "quote.h"
32 #include "xstrtol.h"
33 #include "xdectoint.h"
34 #include "xfreopen.h"
36 #define AUTHORS proper_name ("Simon Josefsson")
38 #if BASE_TYPE == 32
39 # include "base32.h"
40 # define PROGRAM_NAME "base32"
41 #else
42 # include "base64.h"
43 # define PROGRAM_NAME "base64"
44 #endif
47 static struct option const long_options[] =
49 {"decode", no_argument, 0, 'd'},
50 {"wrap", required_argument, 0, 'w'},
51 {"ignore-garbage", no_argument, 0, 'i'},
53 {GETOPT_HELP_OPTION_DECL},
54 {GETOPT_VERSION_OPTION_DECL},
55 {NULL, 0, NULL, 0}
58 void
59 usage (int status)
61 if (status != EXIT_SUCCESS)
62 emit_try_help ();
63 else
65 printf (_("\
66 Usage: %s [OPTION]... [FILE]\n\
67 Base%d encode or decode FILE, or standard input, to standard output.\n\
68 "), program_name, BASE_TYPE);
70 emit_stdin_note ();
71 emit_mandatory_arg_note ();
73 fputs (_("\
74 -d, --decode decode data\n\
75 -i, --ignore-garbage when decoding, ignore non-alphabet characters\n\
76 -w, --wrap=COLS wrap encoded lines after COLS character (default 76).\n\
77 Use 0 to disable line wrapping\n\
78 \n\
79 "), stdout);
80 fputs (HELP_OPTION_DESCRIPTION, stdout);
81 fputs (VERSION_OPTION_DESCRIPTION, stdout);
82 printf (_("\
83 \n\
84 The data are encoded as described for the %s alphabet in RFC 4648.\n\
85 When decoding, the input may contain newlines in addition to the bytes of\n\
86 the formal %s alphabet. Use --ignore-garbage to attempt to recover\n\
87 from any other non-alphabet bytes in the encoded stream.\n"),
88 PROGRAM_NAME, PROGRAM_NAME);
89 emit_ancillary_info (PROGRAM_NAME);
92 exit (status);
95 #define ENC_BLOCKSIZE (1024*3*10)
97 #if BASE_TYPE == 32
98 # define BASE_LENGTH BASE32_LENGTH
99 /* Note that increasing this may decrease performance if --ignore-garbage
100 is used, because of the memmove operation below. */
101 # define DEC_BLOCKSIZE (1024*5)
103 /* Ensure that BLOCKSIZE is a multiple of 5 and 8. */
104 verify (ENC_BLOCKSIZE % 40 == 0); /* So padding chars only on last block. */
105 verify (DEC_BLOCKSIZE % 40 == 0); /* So complete encoded blocks are used. */
107 # define base_encode base32_encode
108 # define base_decode_context base32_decode_context
109 # define base_decode_ctx_init base32_decode_ctx_init
110 # define base_decode_ctx base32_decode_ctx
111 # define isbase isbase32
112 #else
113 # define BASE_LENGTH BASE64_LENGTH
114 /* Note that increasing this may decrease performance if --ignore-garbage
115 is used, because of the memmove operation below. */
116 # define DEC_BLOCKSIZE (1024*3)
118 /* Ensure that BLOCKSIZE is a multiple of 3 and 4. */
119 verify (ENC_BLOCKSIZE % 12 == 0); /* So padding chars only on last block. */
120 verify (DEC_BLOCKSIZE % 12 == 0); /* So complete encoded blocks are used. */
122 # define base_encode base64_encode
123 # define base_decode_context base64_decode_context
124 # define base_decode_ctx_init base64_decode_ctx_init
125 # define base_decode_ctx base64_decode_ctx
126 # define isbase isbase64
127 #endif
129 static void
130 wrap_write (const char *buffer, size_t len,
131 uintmax_t wrap_column, size_t *current_column, FILE *out)
133 size_t written;
135 if (wrap_column == 0)
137 /* Simple write. */
138 if (fwrite (buffer, 1, len, stdout) < len)
139 die (EXIT_FAILURE, errno, _("write error"));
141 else
142 for (written = 0; written < len;)
144 uintmax_t cols_remaining = wrap_column - *current_column;
145 size_t to_write = MIN (cols_remaining, SIZE_MAX);
146 to_write = MIN (to_write, len - written);
148 if (to_write == 0)
150 if (fputc ('\n', out) == EOF)
151 die (EXIT_FAILURE, errno, _("write error"));
152 *current_column = 0;
154 else
156 if (fwrite (buffer + written, 1, to_write, stdout) < to_write)
157 die (EXIT_FAILURE, errno, _("write error"));
158 *current_column += to_write;
159 written += to_write;
164 static void
165 do_encode (FILE *in, FILE *out, uintmax_t wrap_column)
167 size_t current_column = 0;
168 char inbuf[ENC_BLOCKSIZE];
169 char outbuf[BASE_LENGTH (ENC_BLOCKSIZE)];
170 size_t sum;
174 size_t n;
176 sum = 0;
179 n = fread (inbuf + sum, 1, ENC_BLOCKSIZE - sum, in);
180 sum += n;
182 while (!feof (in) && !ferror (in) && sum < ENC_BLOCKSIZE);
184 if (sum > 0)
186 /* Process input one block at a time. Note that ENC_BLOCKSIZE
187 is sized so that no pad chars will appear in output. */
188 base_encode (inbuf, sum, outbuf, BASE_LENGTH (sum));
190 wrap_write (outbuf, BASE_LENGTH (sum), wrap_column,
191 &current_column, out);
194 while (!feof (in) && !ferror (in) && sum == ENC_BLOCKSIZE);
196 /* When wrapping, terminate last line. */
197 if (wrap_column && current_column > 0 && fputc ('\n', out) == EOF)
198 die (EXIT_FAILURE, errno, _("write error"));
200 if (ferror (in))
201 die (EXIT_FAILURE, errno, _("read error"));
204 static void
205 do_decode (FILE *in, FILE *out, bool ignore_garbage)
207 char inbuf[BASE_LENGTH (DEC_BLOCKSIZE)];
208 char outbuf[DEC_BLOCKSIZE];
209 size_t sum;
210 struct base_decode_context ctx;
212 base_decode_ctx_init (&ctx);
216 bool ok;
217 size_t n;
218 unsigned int k;
220 sum = 0;
223 n = fread (inbuf + sum, 1, BASE_LENGTH (DEC_BLOCKSIZE) - sum, in);
225 if (ignore_garbage)
227 size_t i;
228 for (i = 0; n > 0 && i < n;)
229 if (isbase (inbuf[sum + i]) || inbuf[sum + i] == '=')
230 i++;
231 else
232 memmove (inbuf + sum + i, inbuf + sum + i + 1, --n - i);
235 sum += n;
237 if (ferror (in))
238 die (EXIT_FAILURE, errno, _("read error"));
240 while (sum < BASE_LENGTH (DEC_BLOCKSIZE) && !feof (in));
242 /* The following "loop" is usually iterated just once.
243 However, when it processes the final input buffer, we want
244 to iterate it one additional time, but with an indicator
245 telling it to flush what is in CTX. */
246 for (k = 0; k < 1 + !!feof (in); k++)
248 if (k == 1 && ctx.i == 0)
249 break;
250 n = DEC_BLOCKSIZE;
251 ok = base_decode_ctx (&ctx, inbuf, (k == 0 ? sum : 0), outbuf, &n);
253 if (fwrite (outbuf, 1, n, out) < n)
254 die (EXIT_FAILURE, errno, _("write error"));
256 if (!ok)
257 die (EXIT_FAILURE, 0, _("invalid input"));
260 while (!feof (in));
264 main (int argc, char **argv)
266 int opt;
267 FILE *input_fh;
268 const char *infile;
270 /* True if --decode has been given and we should decode data. */
271 bool decode = false;
272 /* True if we should ignore non-base-alphabetic characters. */
273 bool ignore_garbage = false;
274 /* Wrap encoded data around the 76:th column, by default. */
275 uintmax_t wrap_column = 76;
277 initialize_main (&argc, &argv);
278 set_program_name (argv[0]);
279 setlocale (LC_ALL, "");
280 bindtextdomain (PACKAGE, LOCALEDIR);
281 textdomain (PACKAGE);
283 atexit (close_stdout);
285 while ((opt = getopt_long (argc, argv, "diw:", long_options, NULL)) != -1)
286 switch (opt)
288 case 'd':
289 decode = true;
290 break;
292 case 'w':
293 wrap_column = xdectoumax (optarg, 0, UINTMAX_MAX, "",
294 _("invalid wrap size"), 0);
295 break;
297 case 'i':
298 ignore_garbage = true;
299 break;
301 case_GETOPT_HELP_CHAR;
303 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
305 default:
306 usage (EXIT_FAILURE);
307 break;
310 if (argc - optind > 1)
312 error (0, 0, _("extra operand %s"), quote (argv[optind]));
313 usage (EXIT_FAILURE);
316 if (optind < argc)
317 infile = argv[optind];
318 else
319 infile = "-";
321 if (STREQ (infile, "-"))
323 if (O_BINARY)
324 xfreopen (NULL, "rb", stdin);
325 input_fh = stdin;
327 else
329 input_fh = fopen (infile, "rb");
330 if (input_fh == NULL)
331 die (EXIT_FAILURE, errno, "%s", quotef (infile));
334 fadvise (input_fh, FADVISE_SEQUENTIAL);
336 if (decode)
337 do_decode (input_fh, stdout, ignore_garbage);
338 else
339 do_encode (input_fh, stdout, wrap_column);
341 if (fclose (input_fh) == EOF)
343 if (STREQ (infile, "-"))
344 die (EXIT_FAILURE, errno, _("closing standard input"));
345 else
346 die (EXIT_FAILURE, errno, "%s", quotef (infile));
349 return EXIT_SUCCESS;