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>. */
25 #include <sys/types.h>
32 #include "xdectoint.h"
35 #define AUTHORS proper_name ("Simon Josefsson")
39 # define PROGRAM_NAME "base32"
42 # define PROGRAM_NAME "base64"
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
},
60 if (status
!= EXIT_SUCCESS
)
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
);
70 emit_mandatory_arg_note ();
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\
79 fputs (HELP_OPTION_DESCRIPTION
, stdout
);
80 fputs (VERSION_OPTION_DESCRIPTION
, stdout
);
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
);
94 #define ENC_BLOCKSIZE (1024*3*10)
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
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
129 wrap_write (const char *buffer
, size_t len
,
130 uintmax_t wrap_column
, size_t *current_column
, FILE *out
)
134 if (wrap_column
== 0)
137 if (fwrite (buffer
, 1, len
, stdout
) < len
)
138 error (EXIT_FAILURE
, errno
, _("write error"));
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
);
149 if (fputc ('\n', out
) == EOF
)
150 error (EXIT_FAILURE
, errno
, _("write error"));
155 if (fwrite (buffer
+ written
, 1, to_write
, stdout
) < to_write
)
156 error (EXIT_FAILURE
, errno
, _("write error"));
157 *current_column
+= to_write
;
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
)];
178 n
= fread (inbuf
+ sum
, 1, ENC_BLOCKSIZE
- sum
, in
);
181 while (!feof (in
) && !ferror (in
) && sum
< ENC_BLOCKSIZE
);
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 ¤t_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"));
200 error (EXIT_FAILURE
, errno
, _("read error"));
204 do_decode (FILE *in
, FILE *out
, bool ignore_garbage
)
206 char inbuf
[BASE_LENGTH (DEC_BLOCKSIZE
)];
207 char outbuf
[DEC_BLOCKSIZE
];
209 struct base_decode_context ctx
;
211 base_decode_ctx_init (&ctx
);
222 n
= fread (inbuf
+ sum
, 1, BASE_LENGTH (DEC_BLOCKSIZE
) - sum
, in
);
227 for (i
= 0; n
> 0 && i
< n
;)
228 if (isbase (inbuf
[sum
+ i
]) || inbuf
[sum
+ i
] == '=')
231 memmove (inbuf
+ sum
+ i
, inbuf
+ sum
+ i
+ 1, --n
- i
);
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)
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"));
256 error (EXIT_FAILURE
, 0, _("invalid input"));
263 main (int argc
, char **argv
)
269 /* True if --decode has been given and we should decode data. */
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)
292 wrap_column
= xdectoumax (optarg
, 0, UINTMAX_MAX
, "",
293 _("invalid wrap size"), 0);
297 ignore_garbage
= true;
300 case_GETOPT_HELP_CHAR
;
302 case_GETOPT_VERSION_CHAR (PROGRAM_NAME
, AUTHORS
);
305 usage (EXIT_FAILURE
);
309 if (argc
- optind
> 1)
311 error (0, 0, _("extra operand %s"), quote (argv
[optind
]));
312 usage (EXIT_FAILURE
);
316 infile
= argv
[optind
];
320 if (STREQ (infile
, "-"))
323 xfreopen (NULL
, "rb", stdin
);
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
);
336 do_decode (input_fh
, stdout
, ignore_garbage
);
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"));
345 error (EXIT_FAILURE
, errno
, "%s", quotef (infile
));