* src/dd.c (flags): noatime and nofollow now depend on
[coreutils/bo.git] / src / base64.c
blob36afbe4dfb31390b49c1bdb637da56a3bff99f94
1 /* Base64 encode/decode strings or files.
2 Copyright (C) 2004, 2005, 2006 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)
9 any later version.
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>. */
23 #include <config.h>
25 #include <stdio.h>
26 #include <getopt.h>
27 #include <sys/types.h>
29 #include "system.h"
30 #include "error.h"
31 #include "xstrtol.h"
32 #include "quote.h"
33 #include "quotearg.h"
35 #include "base64.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. */
43 char *program_name;
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},
54 {NULL, 0, NULL, 0}
57 static void
58 usage (int status)
60 if (status != EXIT_SUCCESS)
61 fprintf (stderr, _("Try `%s --help' for more information.\n"),
62 program_name);
63 else
65 printf (_("\
66 Usage: %s [OPTION] [FILE]\n\
67 Base64 encode or decode FILE, or standard input, to standard output.\n\
68 \n"), program_name);
69 fputs (_("\
70 -w, --wrap=COLS Wrap encoded lines after COLS character (default 76).\n\
71 Use 0 to disable line wrapping.\n\
72 \n\
73 -d, --decode Decode data.\n\
74 -i, --ignore-garbage When decoding, ignore non-alphabet characters.\n\
75 \n\
76 "), stdout);
77 fputs (_("\
78 --help Display this help and exit.\n\
79 --version Output version information and exit.\n"), stdout);
80 fputs (_("\
81 \n\
82 With no FILE, or when FILE is -, read standard input.\n"), stdout);
83 fputs (_("\
84 \n\
85 The data are encoded as described for the base64 alphabet in RFC 3548.\n\
86 Decoding require compliant input by default, use --ignore-garbage to\n\
87 attempt to recover from non-alphabet characters (such as newlines) in\n\
88 the encoded stream.\n"), stdout);
89 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
92 exit (status);
95 /* Note that increasing this may decrease performance if --ignore-garbage
96 is used, because of the memmove operation below. */
97 #define BLOCKSIZE 3072
98 #define B64BLOCKSIZE BASE64_LENGTH (BLOCKSIZE)
100 /* Ensure that BLOCKSIZE is a multiple of 3 and 4. */
101 #if BLOCKSIZE % 12 != 0
102 # error "invalid BLOCKSIZE"
103 #endif
105 static void
106 wrap_write (const char *buffer, size_t len,
107 uintmax_t wrap_column, size_t *current_column, FILE *out)
109 size_t written;
111 if (wrap_column == 0)
113 /* Simple write. */
114 if (fwrite (buffer, 1, len, stdout) < len)
115 error (EXIT_FAILURE, errno, _("write error"));
117 else
118 for (written = 0; written < len;)
120 uintmax_t cols_remaining = wrap_column - *current_column;
121 size_t to_write = MIN (cols_remaining, SIZE_MAX);
122 to_write = MIN (to_write, len - written);
124 if (to_write == 0)
126 if (fputs ("\n", out) < 0)
127 error (EXIT_FAILURE, errno, _("write error"));
128 *current_column = 0;
130 else
132 if (fwrite (buffer + written, 1, to_write, stdout) < to_write)
133 error (EXIT_FAILURE, errno, _("write error"));
134 *current_column += to_write;
135 written += to_write;
140 static void
141 do_encode (FILE *in, FILE *out, uintmax_t wrap_column)
143 size_t current_column = 0;
144 char inbuf[BLOCKSIZE];
145 char outbuf[B64BLOCKSIZE];
146 size_t sum;
150 size_t n;
152 sum = 0;
155 n = fread (inbuf + sum, 1, BLOCKSIZE - sum, in);
156 sum += n;
158 while (!feof (in) && !ferror (in) && sum < BLOCKSIZE);
160 if (sum > 0)
162 /* Process input one block at a time. Note that BLOCKSIZE %
163 3 == 0, so that no base64 pads will appear in output. */
164 base64_encode (inbuf, sum, outbuf, BASE64_LENGTH (sum));
166 wrap_write (outbuf, BASE64_LENGTH (sum), wrap_column,
167 &current_column, out);
170 while (!feof (in) && !ferror (in) && sum == BLOCKSIZE);
172 /* When wrapping, terminate last line. */
173 if (wrap_column && current_column > 0 && fputs ("\n", out) < 0)
174 error (EXIT_FAILURE, errno, _("write error"));
176 if (ferror (in))
177 error (EXIT_FAILURE, errno, _("read error"));
180 static void
181 do_decode (FILE *in, FILE *out, bool ignore_garbage)
183 char inbuf[B64BLOCKSIZE];
184 char outbuf[BLOCKSIZE];
185 size_t sum;
189 bool ok;
190 size_t n;
192 sum = 0;
195 n = fread (inbuf + sum, 1, B64BLOCKSIZE - sum, in);
197 if (ignore_garbage)
199 size_t i;
200 for (i = 0; n > 0 && i < n;)
201 if (isbase64 (inbuf[sum + i]) || inbuf[sum + i] == '=')
202 i++;
203 else
204 memmove (inbuf + sum + i, inbuf + sum + i + 1, --n - i);
207 sum += n;
209 if (ferror (in))
210 error (EXIT_FAILURE, errno, _("read error"));
212 while (sum < B64BLOCKSIZE && !feof (in));
214 n = BLOCKSIZE;
215 ok = base64_decode (inbuf, sum, outbuf, &n);
217 if (fwrite (outbuf, 1, n, out) < n)
218 error (EXIT_FAILURE, errno, _("write error"));
220 if (!ok)
221 error (EXIT_FAILURE, 0, _("invalid input"));
223 while (!feof (in));
227 main (int argc, char **argv)
229 int opt;
230 FILE *input_fh;
231 const char *infile;
233 /* True if --decode has bene given and we should decode data. */
234 bool decode = false;
235 /* True if we should ignore non-alphabetic characters. */
236 bool ignore_garbage = false;
237 /* Wrap encoded base64 data around the 76:th column, by default. */
238 uintmax_t wrap_column = 76;
240 initialize_main (&argc, &argv);
241 program_name = argv[0];
242 setlocale (LC_ALL, "");
243 bindtextdomain (PACKAGE, LOCALEDIR);
244 textdomain (PACKAGE);
246 atexit (close_stdout);
248 while ((opt = getopt_long (argc, argv, "dqiw:", long_options, NULL)) != -1)
249 switch (opt)
251 case 'd':
252 decode = true;
253 break;
255 case 'w':
256 if (xstrtoumax (optarg, NULL, 0, &wrap_column, NULL) != LONGINT_OK)
257 error (EXIT_FAILURE, 0, _("invalid wrap size: %s"),
258 quotearg (optarg));
259 break;
261 case 'i':
262 ignore_garbage = true;
263 break;
265 case_GETOPT_HELP_CHAR;
267 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHOR);
269 default:
270 usage (EXIT_FAILURE);
271 break;
274 if (argc - optind > 1)
276 error (0, 0, _("extra operand %s"), quote (argv[optind]));
277 usage (EXIT_FAILURE);
280 if (optind < argc)
281 infile = argv[optind];
282 else
283 infile = "-";
285 if (strcmp (infile, "-") == 0)
286 input_fh = stdin;
287 else
289 input_fh = fopen (infile, "r");
290 if (input_fh == NULL)
291 error (EXIT_FAILURE, errno, "%s", infile);
294 if (decode)
295 do_decode (input_fh, stdout, ignore_garbage);
296 else
297 do_encode (input_fh, stdout, wrap_column);
299 if (fclose (input_fh) == EOF)
301 if (strcmp (infile, "-") == 0)
302 error (EXIT_FAILURE, errno, _("closing standard input"));
303 else
304 error (EXIT_FAILURE, errno, "%s", infile);
307 exit (EXIT_SUCCESS);