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)
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>. */
27 #include <sys/types.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. */
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
},
60 if (status
!= EXIT_SUCCESS
)
61 fprintf (stderr
, _("Try `%s --help' for more information.\n"),
66 Usage: %s [OPTION] [FILE]\n\
67 Base64 encode or decode FILE, or standard input, to standard output.\n\
70 -w, --wrap=COLS Wrap encoded lines after COLS character (default 76).\n\
71 Use 0 to disable line wrapping.\n\
73 -d, --decode Decode data.\n\
74 -i, --ignore-garbage When decoding, ignore non-alphabet characters.\n\
78 --help Display this help and exit.\n\
79 --version Output version information and exit.\n"), stdout
);
82 With no FILE, or when FILE is -, read standard input.\n"), stdout
);
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
);
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"
106 wrap_write (const char *buffer
, size_t len
,
107 uintmax_t wrap_column
, size_t *current_column
, FILE *out
)
111 if (wrap_column
== 0)
114 if (fwrite (buffer
, 1, len
, stdout
) < len
)
115 error (EXIT_FAILURE
, errno
, _("write error"));
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
);
126 if (fputs ("\n", out
) < 0)
127 error (EXIT_FAILURE
, errno
, _("write error"));
132 if (fwrite (buffer
+ written
, 1, to_write
, stdout
) < to_write
)
133 error (EXIT_FAILURE
, errno
, _("write error"));
134 *current_column
+= to_write
;
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
];
155 n
= fread (inbuf
+ sum
, 1, BLOCKSIZE
- sum
, in
);
158 while (!feof (in
) && !ferror (in
) && sum
< BLOCKSIZE
);
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 ¤t_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"));
177 error (EXIT_FAILURE
, errno
, _("read error"));
181 do_decode (FILE *in
, FILE *out
, bool ignore_garbage
)
183 char inbuf
[B64BLOCKSIZE
];
184 char outbuf
[BLOCKSIZE
];
195 n
= fread (inbuf
+ sum
, 1, B64BLOCKSIZE
- sum
, in
);
200 for (i
= 0; n
> 0 && i
< n
;)
201 if (isbase64 (inbuf
[sum
+ i
]) || inbuf
[sum
+ i
] == '=')
204 memmove (inbuf
+ sum
+ i
, inbuf
+ sum
+ i
+ 1, --n
- i
);
210 error (EXIT_FAILURE
, errno
, _("read error"));
212 while (sum
< B64BLOCKSIZE
&& !feof (in
));
215 ok
= base64_decode (inbuf
, sum
, outbuf
, &n
);
217 if (fwrite (outbuf
, 1, n
, out
) < n
)
218 error (EXIT_FAILURE
, errno
, _("write error"));
221 error (EXIT_FAILURE
, 0, _("invalid input"));
227 main (int argc
, char **argv
)
233 /* True if --decode has bene given and we should decode data. */
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)
256 if (xstrtoumax (optarg
, NULL
, 0, &wrap_column
, NULL
) != LONGINT_OK
)
257 error (EXIT_FAILURE
, 0, _("invalid wrap size: %s"),
262 ignore_garbage
= true;
265 case_GETOPT_HELP_CHAR
;
267 case_GETOPT_VERSION_CHAR (PROGRAM_NAME
, AUTHOR
);
270 usage (EXIT_FAILURE
);
274 if (argc
- optind
> 1)
276 error (0, 0, _("extra operand %s"), quote (argv
[optind
]));
277 usage (EXIT_FAILURE
);
281 infile
= argv
[optind
];
285 if (strcmp (infile
, "-") == 0)
289 input_fh
= fopen (infile
, "r");
290 if (input_fh
== NULL
)
291 error (EXIT_FAILURE
, errno
, "%s", infile
);
295 do_decode (input_fh
, stdout
, ignore_garbage
);
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"));
304 error (EXIT_FAILURE
, errno
, "%s", infile
);