1 /* Base64 encode/decode strings or files.
2 Copyright (C) 2004-2013 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>. */
25 #include <sys/types.h>
37 /* The official name of this program (e.g., no 'g' prefix). */
38 #define PROGRAM_NAME "base64"
40 #define AUTHORS proper_name ("Simon Josefsson")
42 static struct option
const long_options
[] =
44 {"decode", no_argument
, 0, 'd'},
45 {"wrap", required_argument
, 0, 'w'},
46 {"ignore-garbage", no_argument
, 0, 'i'},
48 {GETOPT_HELP_OPTION_DECL
},
49 {GETOPT_VERSION_OPTION_DECL
},
56 if (status
!= EXIT_SUCCESS
)
61 Usage: %s [OPTION]... [FILE]\n\
62 Base64 encode or decode FILE, or standard input, to standard output.\n\
65 emit_mandatory_arg_note ();
68 -d, --decode decode data\n\
69 -i, --ignore-garbage when decoding, ignore non-alphabet characters\n\
70 -w, --wrap=COLS wrap encoded lines after COLS character (default 76).\n\
71 Use 0 to disable line wrapping\n\
74 fputs (HELP_OPTION_DESCRIPTION
, stdout
);
75 fputs (VERSION_OPTION_DESCRIPTION
, stdout
);
78 With no FILE, or when FILE is -, read standard input.\n"), stdout
);
81 The data are encoded as described for the base64 alphabet in RFC 3548.\n\
82 When decoding, the input may contain newlines in addition to the bytes of\n\
83 the formal base64 alphabet. Use --ignore-garbage to attempt to recover\n\
84 from any other non-alphabet bytes in the encoded stream.\n"),
86 emit_ancillary_info ();
92 #define ENC_BLOCKSIZE (1024*3*10)
93 #define ENC_B64BLOCKSIZE BASE64_LENGTH (ENC_BLOCKSIZE)
94 /* Note that increasing this may decrease performance if --ignore-garbage
95 is used, because of the memmove operation below. */
96 #define DEC_BLOCKSIZE (1024*3)
97 #define DEC_B64BLOCKSIZE BASE64_LENGTH (DEC_BLOCKSIZE)
99 /* Ensure that BLOCKSIZE is a multiple of 3 and 4. */
100 verify (ENC_BLOCKSIZE
% 12 == 0);
101 verify (DEC_BLOCKSIZE
% 12 == 0);
104 wrap_write (const char *buffer
, size_t len
,
105 uintmax_t wrap_column
, size_t *current_column
, FILE *out
)
109 if (wrap_column
== 0)
112 if (fwrite (buffer
, 1, len
, stdout
) < len
)
113 error (EXIT_FAILURE
, errno
, _("write error"));
116 for (written
= 0; written
< len
;)
118 uintmax_t cols_remaining
= wrap_column
- *current_column
;
119 size_t to_write
= MIN (cols_remaining
, SIZE_MAX
);
120 to_write
= MIN (to_write
, len
- written
);
124 if (fputc ('\n', out
) == EOF
)
125 error (EXIT_FAILURE
, errno
, _("write error"));
130 if (fwrite (buffer
+ written
, 1, to_write
, stdout
) < to_write
)
131 error (EXIT_FAILURE
, errno
, _("write error"));
132 *current_column
+= to_write
;
139 do_encode (FILE *in
, FILE *out
, uintmax_t wrap_column
)
141 size_t current_column
= 0;
142 char inbuf
[ENC_BLOCKSIZE
];
143 char outbuf
[ENC_B64BLOCKSIZE
];
153 n
= fread (inbuf
+ sum
, 1, ENC_BLOCKSIZE
- sum
, in
);
156 while (!feof (in
) && !ferror (in
) && sum
< ENC_BLOCKSIZE
);
160 /* Process input one block at a time. Note that ENC_BLOCKSIZE %
161 3 == 0, so that no base64 pads will appear in output. */
162 base64_encode (inbuf
, sum
, outbuf
, BASE64_LENGTH (sum
));
164 wrap_write (outbuf
, BASE64_LENGTH (sum
), wrap_column
,
165 ¤t_column
, out
);
168 while (!feof (in
) && !ferror (in
) && sum
== ENC_BLOCKSIZE
);
170 /* When wrapping, terminate last line. */
171 if (wrap_column
&& current_column
> 0 && fputc ('\n', out
) == EOF
)
172 error (EXIT_FAILURE
, errno
, _("write error"));
175 error (EXIT_FAILURE
, errno
, _("read error"));
179 do_decode (FILE *in
, FILE *out
, bool ignore_garbage
)
181 char inbuf
[DEC_B64BLOCKSIZE
];
182 char outbuf
[DEC_BLOCKSIZE
];
184 struct base64_decode_context ctx
;
186 base64_decode_ctx_init (&ctx
);
197 n
= fread (inbuf
+ sum
, 1, DEC_B64BLOCKSIZE
- sum
, in
);
202 for (i
= 0; n
> 0 && i
< n
;)
203 if (isbase64 (inbuf
[sum
+ i
]) || inbuf
[sum
+ i
] == '=')
206 memmove (inbuf
+ sum
+ i
, inbuf
+ sum
+ i
+ 1, --n
- i
);
212 error (EXIT_FAILURE
, errno
, _("read error"));
214 while (sum
< DEC_B64BLOCKSIZE
&& !feof (in
));
216 /* The following "loop" is usually iterated just once.
217 However, when it processes the final input buffer, we want
218 to iterate it one additional time, but with an indicator
219 telling it to flush what is in CTX. */
220 for (k
= 0; k
< 1 + !!feof (in
); k
++)
222 if (k
== 1 && ctx
.i
== 0)
225 ok
= base64_decode_ctx (&ctx
, inbuf
, (k
== 0 ? sum
: 0), outbuf
, &n
);
227 if (fwrite (outbuf
, 1, n
, out
) < n
)
228 error (EXIT_FAILURE
, errno
, _("write error"));
231 error (EXIT_FAILURE
, 0, _("invalid input"));
238 main (int argc
, char **argv
)
244 /* True if --decode has been given and we should decode data. */
246 /* True if we should ignore non-base64-alphabetic characters. */
247 bool ignore_garbage
= false;
248 /* Wrap encoded base64 data around the 76:th column, by default. */
249 uintmax_t wrap_column
= 76;
251 initialize_main (&argc
, &argv
);
252 set_program_name (argv
[0]);
253 setlocale (LC_ALL
, "");
254 bindtextdomain (PACKAGE
, LOCALEDIR
);
255 textdomain (PACKAGE
);
257 atexit (close_stdout
);
259 while ((opt
= getopt_long (argc
, argv
, "diw:", long_options
, NULL
)) != -1)
267 if (xstrtoumax (optarg
, NULL
, 0, &wrap_column
, NULL
) != LONGINT_OK
)
268 error (EXIT_FAILURE
, 0, _("invalid wrap size: %s"),
273 ignore_garbage
= true;
276 case_GETOPT_HELP_CHAR
;
278 case_GETOPT_VERSION_CHAR (PROGRAM_NAME
, AUTHORS
);
281 usage (EXIT_FAILURE
);
285 if (argc
- optind
> 1)
287 error (0, 0, _("extra operand %s"), quote (argv
[optind
]));
288 usage (EXIT_FAILURE
);
292 infile
= argv
[optind
];
296 if (STREQ (infile
, "-"))
299 xfreopen (NULL
, "rb", stdin
);
304 input_fh
= fopen (infile
, "rb");
305 if (input_fh
== NULL
)
306 error (EXIT_FAILURE
, errno
, "%s", infile
);
309 fadvise (input_fh
, FADVISE_SEQUENTIAL
);
312 do_decode (input_fh
, stdout
, ignore_garbage
);
314 do_encode (input_fh
, stdout
, wrap_column
);
316 if (fclose (input_fh
) == EOF
)
318 if (STREQ (infile
, "-"))
319 error (EXIT_FAILURE
, errno
, _("closing standard input"));
321 error (EXIT_FAILURE
, errno
, "%s", infile
);