1 /* Base64, base32, and similar encoding/decoding strings or files.
2 Copyright (C) 2004-2023 Free Software Foundation, Inc.
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17 /* Written by Simon Josefsson <simon@josefsson.org>. */
18
19 #include <config.h>
20
21 #include <stdio.h>
22 #include <getopt.h>
23 #include <sys/types.h>
24
25 #include "system.h"
26 #include "assure.h"
27 #include "c-ctype.h"
28 #include "fadvise.h"
29 #include "quote.h"
30 #include "xstrtol.h"
31 #include "xdectoint.h"
32 #include "xbinary-io.h"
33
34 #if BASE_TYPE == 42
35 # define AUTHORS \
36 proper_name ("Simon Josefsson"), \
37 proper_name ("Assaf Gordon")
38 #else
39 # define AUTHORS proper_name ("Simon Josefsson")
40 #endif
41
42 #if BASE_TYPE == 32
43 # include "base32.h"
44 # define PROGRAM_NAME "base32"
45 #elif BASE_TYPE == 64
46 # include "base64.h"
47 # define PROGRAM_NAME "base64"
48 #elif BASE_TYPE == 42
49 # include "base32.h"
50 # include "base64.h"
51 # include "assure.h"
52 # define PROGRAM_NAME "basenc"
53 #else
54 # error missing/invalid BASE_TYPE definition
55 #endif
56
57
58
59 #if BASE_TYPE == 42
60 enum
61 {
62 BASE64_OPTION = CHAR_MAX + 1,
63 BASE64URL_OPTION,
64 BASE32_OPTION,
65 BASE32HEX_OPTION,
66 BASE16_OPTION,
67 BASE2MSBF_OPTION,
68 BASE2LSBF_OPTION,
69 Z85_OPTION
70 };
71 #endif
72
73 static struct option const long_options[] =
74 {
75 {"decode", no_argument, 0, 'd'},
76 {"wrap", required_argument, 0, 'w'},
77 {"ignore-garbage", no_argument, 0, 'i'},
78 #if BASE_TYPE == 42
79 {"base64", no_argument, 0, BASE64_OPTION},
80 {"base64url", no_argument, 0, BASE64URL_OPTION},
81 {"base32", no_argument, 0, BASE32_OPTION},
82 {"base32hex", no_argument, 0, BASE32HEX_OPTION},
83 {"base16", no_argument, 0, BASE16_OPTION},
84 {"base2msbf", no_argument, 0, BASE2MSBF_OPTION},
85 {"base2lsbf", no_argument, 0, BASE2LSBF_OPTION},
86 {"z85", no_argument, 0, Z85_OPTION},
87 #endif
88 {GETOPT_HELP_OPTION_DECL},
89 {GETOPT_VERSION_OPTION_DECL},
90 {nullptr, 0, nullptr, 0}
91 };
92
93 void
usage(int status)94 usage (int status)
95 {
96 if (status != EXIT_SUCCESS)
97 emit_try_help ();
98 else
99 {
100 printf (_("\
101 Usage: %s [OPTION]... [FILE]\n\
102 "), program_name);
103
104 #if BASE_TYPE == 42
105 fputs (_("\
106 basenc encode or decode FILE, or standard input, to standard output.\n\
107 "), stdout);
108 #else
109 printf (_("\
110 Base%d encode or decode FILE, or standard input, to standard output.\n\
111 "), BASE_TYPE);
112 #endif
113
114 emit_stdin_note ();
115 emit_mandatory_arg_note ();
116 #if BASE_TYPE == 42
117 fputs (_("\
118 --base64 same as 'base64' program (RFC4648 section 4)\n\
119 "), stdout);
120 fputs (_("\
121 --base64url file- and url-safe base64 (RFC4648 section 5)\n\
122 "), stdout);
123 fputs (_("\
124 --base32 same as 'base32' program (RFC4648 section 6)\n\
125 "), stdout);
126 fputs (_("\
127 --base32hex extended hex alphabet base32 (RFC4648 section 7)\n\
128 "), stdout);
129 fputs (_("\
130 --base16 hex encoding (RFC4648 section 8)\n\
131 "), stdout);
132 fputs (_("\
133 --base2msbf bit string with most significant bit (msb) first\n\
134 "), stdout);
135 fputs (_("\
136 --base2lsbf bit string with least significant bit (lsb) first\n\
137 "), stdout);
138 #endif
139 fputs (_("\
140 -d, --decode decode data\n\
141 -i, --ignore-garbage when decoding, ignore non-alphabet characters\n\
142 -w, --wrap=COLS wrap encoded lines after COLS character (default 76).\n\
143 Use 0 to disable line wrapping\n\
144 "), stdout);
145 #if BASE_TYPE == 42
146 fputs (_("\
147 --z85 ascii85-like encoding (ZeroMQ spec:32/Z85);\n\
148 when encoding, input length must be a multiple of 4;\n\
149 when decoding, input length must be a multiple of 5\n\
150 "), stdout);
151 #endif
152 fputs (HELP_OPTION_DESCRIPTION, stdout);
153 fputs (VERSION_OPTION_DESCRIPTION, stdout);
154 #if BASE_TYPE == 42
155 fputs (_("\
156 \n\
157 When decoding, the input may contain newlines in addition to the bytes of\n\
158 the formal alphabet. Use --ignore-garbage to attempt to recover\n\
159 from any other non-alphabet bytes in the encoded stream.\n\
160 "), stdout);
161 #else
162 printf (_("\
163 \n\
164 The data are encoded as described for the %s alphabet in RFC 4648.\n\
165 When decoding, the input may contain newlines in addition to the bytes of\n\
166 the formal %s alphabet. Use --ignore-garbage to attempt to recover\n\
167 from any other non-alphabet bytes in the encoded stream.\n"),
168 PROGRAM_NAME, PROGRAM_NAME);
169 #endif
170 emit_ancillary_info (PROGRAM_NAME);
171 }
172
173 exit (status);
174 }
175
176 #if BASE_TYPE != 64
177 static int
base32_required_padding(int len)178 base32_required_padding (int len)
179 {
180 int partial = len % 8;
181 return partial ? 8 - partial : 0;
182 }
183 #endif
184
185 #if BASE_TYPE != 32
186 static int
base64_required_padding(int len)187 base64_required_padding (int len)
188 {
189 int partial = len % 4;
190 return partial ? 4 - partial : 0;
191 }
192 #endif
193
194 #if BASE_TYPE == 42
195 static int
no_required_padding(int len)196 no_required_padding (int len)
197 {
198 return 0;
199 }
200 #endif
201
202 #define ENC_BLOCKSIZE (1024 * 3 * 10)
203
204 #if BASE_TYPE == 32
205 # define BASE_LENGTH BASE32_LENGTH
206 # define REQUIRED_PADDING base32_required_padding
207 /* Note that increasing this may decrease performance if --ignore-garbage
208 is used, because of the memmove operation below. */
209 # define DEC_BLOCKSIZE (1024 * 5)
210
211 /* Ensure that BLOCKSIZE is a multiple of 5 and 8. */
212 static_assert (ENC_BLOCKSIZE % 40 == 0); /* Padding chars only on last block. */
213 static_assert (DEC_BLOCKSIZE % 40 == 0); /* Complete encoded blocks are used. */
214
215 # define base_encode base32_encode
216 # define base_decode_context base32_decode_context
217 # define base_decode_ctx_init base32_decode_ctx_init
218 # define base_decode_ctx base32_decode_ctx
219 # define isubase isubase32
220 #elif BASE_TYPE == 64
221 # define BASE_LENGTH BASE64_LENGTH
222 # define REQUIRED_PADDING base64_required_padding
223 /* Note that increasing this may decrease performance if --ignore-garbage
224 is used, because of the memmove operation below. */
225 # define DEC_BLOCKSIZE (1024 * 3)
226
227 /* Ensure that BLOCKSIZE is a multiple of 3 and 4. */
228 static_assert (ENC_BLOCKSIZE % 12 == 0); /* Padding chars only on last block. */
229 static_assert (DEC_BLOCKSIZE % 12 == 0); /* Complete encoded blocks are used. */
230
231 # define base_encode base64_encode
232 # define base_decode_context base64_decode_context
233 # define base_decode_ctx_init base64_decode_ctx_init
234 # define base_decode_ctx base64_decode_ctx
235 # define isubase isubase64
236 #elif BASE_TYPE == 42
237
238
239 # define BASE_LENGTH base_length
240 # define REQUIRED_PADDING required_padding
241
242 /* Note that increasing this may decrease performance if --ignore-garbage
243 is used, because of the memmove operation below. */
244 # define DEC_BLOCKSIZE (4200)
245 static_assert (DEC_BLOCKSIZE % 40 == 0); /* complete encoded blocks for base32*/
246 static_assert (DEC_BLOCKSIZE % 12 == 0); /* complete encoded blocks for base64*/
247
248 static int (*base_length) (int i);
249 static int (*required_padding) (int i);
250 static bool (*isubase) (unsigned char ch);
251 static void (*base_encode) (char const *restrict in, idx_t inlen,
252 char *restrict out, idx_t outlen);
253
254 struct base16_decode_context
255 {
256 /* Either a 4-bit nibble, or negative if we have no nibble. */
257 signed char nibble;
258 };
259
260 struct z85_decode_context
261 {
262 int i;
263 unsigned char octets[5];
264 };
265
266 struct base2_decode_context
267 {
268 unsigned char octet;
269 };
270
271 struct base_decode_context
272 {
273 int i; /* will be updated manually */
274 union {
275 struct base64_decode_context base64;
276 struct base32_decode_context base32;
277 struct base16_decode_context base16;
278 struct base2_decode_context base2;
279 struct z85_decode_context z85;
280 } ctx;
281 char *inbuf;
282 idx_t bufsize;
283 };
284 static void (*base_decode_ctx_init) (struct base_decode_context *ctx);
285 static bool (*base_decode_ctx) (struct base_decode_context *ctx,
286 char const *restrict in, idx_t inlen,
287 char *restrict out, idx_t *outlen);
288 #endif
289
290
291
292
293 #if BASE_TYPE == 42
294
295 static int
base64_length_wrapper(int len)296 base64_length_wrapper (int len)
297 {
298 return BASE64_LENGTH (len);
299 }
300
301 static void
base64_decode_ctx_init_wrapper(struct base_decode_context * ctx)302 base64_decode_ctx_init_wrapper (struct base_decode_context *ctx)
303 {
304 base64_decode_ctx_init (&ctx->ctx.base64);
305 }
306
307 static bool
base64_decode_ctx_wrapper(struct base_decode_context * ctx,char const * restrict in,idx_t inlen,char * restrict out,idx_t * outlen)308 base64_decode_ctx_wrapper (struct base_decode_context *ctx,
309 char const *restrict in, idx_t inlen,
310 char *restrict out, idx_t *outlen)
311 {
312 bool b = base64_decode_ctx (&ctx->ctx.base64, in, inlen, out, outlen);
313 ctx->i = ctx->ctx.base64.i;
314 return b;
315 }
316
317 static void
init_inbuf(struct base_decode_context * ctx)318 init_inbuf (struct base_decode_context *ctx)
319 {
320 ctx->bufsize = DEC_BLOCKSIZE;
321 ctx->inbuf = xcharalloc (ctx->bufsize);
322 }
323
324 static void
prepare_inbuf(struct base_decode_context * ctx,idx_t inlen)325 prepare_inbuf (struct base_decode_context *ctx, idx_t inlen)
326 {
327 if (ctx->bufsize < inlen)
328 {
329 ctx->bufsize = inlen * 2;
330 ctx->inbuf = xnrealloc (ctx->inbuf, ctx->bufsize, sizeof (char));
331 }
332 }
333
334
335 static void
base64url_encode(char const * restrict in,idx_t inlen,char * restrict out,idx_t outlen)336 base64url_encode (char const *restrict in, idx_t inlen,
337 char *restrict out, idx_t outlen)
338 {
339 base64_encode (in, inlen, out, outlen);
340 /* translate 62nd and 63rd characters */
341 char *p = out;
342 while (outlen--)
343 {
344 if (*p == '+')
345 *p = '-';
346 else if (*p == '/')
347 *p = '_';
348 ++p;
349 }
350 }
351
352 static bool
isubase64url(unsigned char ch)353 isubase64url (unsigned char ch)
354 {
355 return (ch == '-' || ch == '_'
356 || (ch != '+' && ch != '/' && isubase64 (ch)));
357 }
358
359 static void
base64url_decode_ctx_init_wrapper(struct base_decode_context * ctx)360 base64url_decode_ctx_init_wrapper (struct base_decode_context *ctx)
361 {
362 base64_decode_ctx_init (&ctx->ctx.base64);
363 init_inbuf (ctx);
364 }
365
366
367 static bool
base64url_decode_ctx_wrapper(struct base_decode_context * ctx,char const * restrict in,idx_t inlen,char * restrict out,idx_t * outlen)368 base64url_decode_ctx_wrapper (struct base_decode_context *ctx,
369 char const *restrict in, idx_t inlen,
370 char *restrict out, idx_t *outlen)
371 {
372 prepare_inbuf (ctx, inlen);
373 memcpy (ctx->inbuf, in, inlen);
374
375 /* translate 62nd and 63rd characters */
376 idx_t i = inlen;
377 char *p = ctx->inbuf;
378 while (i--)
379 {
380 if (*p == '+' || *p == '/')
381 {
382 *outlen = 0;
383 return false; /* reject base64 input */
384 }
385 else if (*p == '-')
386 *p = '+';
387 else if (*p == '_')
388 *p = '/';
389 ++p;
390 }
391
392 bool b = base64_decode_ctx (&ctx->ctx.base64, ctx->inbuf, inlen,
393 out, outlen);
394 ctx->i = ctx->ctx.base64.i;
395
396 return b;
397 }
398
399
400
401 static int
base32_length_wrapper(int len)402 base32_length_wrapper (int len)
403 {
404 return BASE32_LENGTH (len);
405 }
406
407 static void
base32_decode_ctx_init_wrapper(struct base_decode_context * ctx)408 base32_decode_ctx_init_wrapper (struct base_decode_context *ctx)
409 {
410 base32_decode_ctx_init (&ctx->ctx.base32);
411 }
412
413 static bool
base32_decode_ctx_wrapper(struct base_decode_context * ctx,char const * restrict in,idx_t inlen,char * restrict out,idx_t * outlen)414 base32_decode_ctx_wrapper (struct base_decode_context *ctx,
415 char const *restrict in, idx_t inlen,
416 char *restrict out, idx_t *outlen)
417 {
418 bool b = base32_decode_ctx (&ctx->ctx.base32, in, inlen, out, outlen);
419 ctx->i = ctx->ctx.base32.i;
420 return b;
421 }
422
423 /* ABCDEFGHIJKLMNOPQRSTUVWXYZ234567
424 to
425 0123456789ABCDEFGHIJKLMNOPQRSTUV */
426 static const char base32_norm_to_hex[32 + 9] = {
427 /*0x32, 0x33, 0x34, 0x35, 0x36, 0x37, */
428 'Q', 'R', 'S', 'T', 'U', 'V',
429
430 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40,
431
432 /*0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, */
433 '0', '1', '2', '3', '4', '5', '6', '7',
434
435 /*0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, */
436 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
437
438 /*0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, */
439 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
440
441 /*0x59, 0x5a, */
442 'O', 'P',
443 };
444
445 /* 0123456789ABCDEFGHIJKLMNOPQRSTUV
446 to
447 ABCDEFGHIJKLMNOPQRSTUVWXYZ234567 */
448 static const char base32_hex_to_norm[32 + 9] = {
449 /* from: 0x30 .. 0x39 ('0' to '9') */
450 /* to:*/ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
451
452 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40,
453
454 /* from: 0x41 .. 0x4A ('A' to 'J') */
455 /* to:*/ 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
456
457 /* from: 0x4B .. 0x54 ('K' to 'T') */
458 /* to:*/ 'U', 'V', 'W', 'X', 'Y', 'Z', '2', '3', '4', '5',
459
460 /* from: 0x55 .. 0x56 ('U' to 'V') */
461 /* to:*/ '6', '7'
462 };
463
464
465 inline static bool
isubase32hex(unsigned char ch)466 isubase32hex (unsigned char ch)
467 {
468 return ('0' <= ch && ch <= '9') || ('A' <= ch && ch <= 'V');
469 }
470
471
472 static void
base32hex_encode(char const * restrict in,idx_t inlen,char * restrict out,idx_t outlen)473 base32hex_encode (char const *restrict in, idx_t inlen,
474 char *restrict out, idx_t outlen)
475 {
476 base32_encode (in, inlen, out, outlen);
477
478 for (char *p = out; outlen--; p++)
479 {
480 affirm (0x32 <= *p && *p <= 0x5a); /* LCOV_EXCL_LINE */
481 *p = base32_norm_to_hex[*p - 0x32];
482 }
483 }
484
485
486 static void
base32hex_decode_ctx_init_wrapper(struct base_decode_context * ctx)487 base32hex_decode_ctx_init_wrapper (struct base_decode_context *ctx)
488 {
489 base32_decode_ctx_init (&ctx->ctx.base32);
490 init_inbuf (ctx);
491 }
492
493
494 static bool
base32hex_decode_ctx_wrapper(struct base_decode_context * ctx,char const * restrict in,idx_t inlen,char * restrict out,idx_t * outlen)495 base32hex_decode_ctx_wrapper (struct base_decode_context *ctx,
496 char const *restrict in, idx_t inlen,
497 char *restrict out, idx_t *outlen)
498 {
499 prepare_inbuf (ctx, inlen);
500
501 idx_t i = inlen;
502 char *p = ctx->inbuf;
503 while (i--)
504 {
505 if (isubase32hex (*in))
506 *p = base32_hex_to_norm[*in - 0x30];
507 else
508 *p = *in;
509 ++p;
510 ++in;
511 }
512
513 bool b = base32_decode_ctx (&ctx->ctx.base32, ctx->inbuf, inlen,
514 out, outlen);
515 ctx->i = ctx->ctx.base32.i;
516
517 return b;
518 }
519 /* With this approach this file works independent of the charset used
520 (think EBCDIC). However, it does assume that the characters in the
521 Base32 alphabet (A-Z2-7) are encoded in 0..255. POSIX
522 1003.1-2001 require that char and unsigned char are 8-bit
523 quantities, though, taking care of that problem. But this may be a
524 potential problem on non-POSIX C99 platforms.
525
526 IBM C V6 for AIX mishandles "#define B32(x) ...'x'...", so use "_"
527 as the formal parameter rather than "x". */
528 #define B16(_) \
529 ((_) == '0' ? 0 \
530 : (_) == '1' ? 1 \
531 : (_) == '2' ? 2 \
532 : (_) == '3' ? 3 \
533 : (_) == '4' ? 4 \
534 : (_) == '5' ? 5 \
535 : (_) == '6' ? 6 \
536 : (_) == '7' ? 7 \
537 : (_) == '8' ? 8 \
538 : (_) == '9' ? 9 \
539 : (_) == 'A' || (_) == 'a' ? 10 \
540 : (_) == 'B' || (_) == 'b' ? 11 \
541 : (_) == 'C' || (_) == 'c' ? 12 \
542 : (_) == 'D' || (_) == 'd' ? 13 \
543 : (_) == 'E' || (_) == 'e' ? 14 \
544 : (_) == 'F' || (_) == 'f' ? 15 \
545 : -1)
546
547 static signed char const base16_to_int[256] = {
548 B16 (0), B16 (1), B16 (2), B16 (3),
549 B16 (4), B16 (5), B16 (6), B16 (7),
550 B16 (8), B16 (9), B16 (10), B16 (11),
551 B16 (12), B16 (13), B16 (14), B16 (15),
552 B16 (16), B16 (17), B16 (18), B16 (19),
553 B16 (20), B16 (21), B16 (22), B16 (23),
554 B16 (24), B16 (25), B16 (26), B16 (27),
555 B16 (28), B16 (29), B16 (30), B16 (31),
556 B16 (32), B16 (33), B16 (34), B16 (35),
557 B16 (36), B16 (37), B16 (38), B16 (39),
558 B16 (40), B16 (41), B16 (42), B16 (43),
559 B16 (44), B16 (45), B16 (46), B16 (47),
560 B16 (48), B16 (49), B16 (50), B16 (51),
561 B16 (52), B16 (53), B16 (54), B16 (55),
562 B16 (56), B16 (57), B16 (58), B16 (59),
563 B16 (60), B16 (61), B16 (62), B16 (63),
564 B16 (32), B16 (65), B16 (66), B16 (67),
565 B16 (68), B16 (69), B16 (70), B16 (71),
566 B16 (72), B16 (73), B16 (74), B16 (75),
567 B16 (76), B16 (77), B16 (78), B16 (79),
568 B16 (80), B16 (81), B16 (82), B16 (83),
569 B16 (84), B16 (85), B16 (86), B16 (87),
570 B16 (88), B16 (89), B16 (90), B16 (91),
571 B16 (92), B16 (93), B16 (94), B16 (95),
572 B16 (96), B16 (97), B16 (98), B16 (99),
573 B16 (100), B16 (101), B16 (102), B16 (103),
574 B16 (104), B16 (105), B16 (106), B16 (107),
575 B16 (108), B16 (109), B16 (110), B16 (111),
576 B16 (112), B16 (113), B16 (114), B16 (115),
577 B16 (116), B16 (117), B16 (118), B16 (119),
578 B16 (120), B16 (121), B16 (122), B16 (123),
579 B16 (124), B16 (125), B16 (126), B16 (127),
580 B16 (128), B16 (129), B16 (130), B16 (131),
581 B16 (132), B16 (133), B16 (134), B16 (135),
582 B16 (136), B16 (137), B16 (138), B16 (139),
583 B16 (140), B16 (141), B16 (142), B16 (143),
584 B16 (144), B16 (145), B16 (146), B16 (147),
585 B16 (148), B16 (149), B16 (150), B16 (151),
586 B16 (152), B16 (153), B16 (154), B16 (155),
587 B16 (156), B16 (157), B16 (158), B16 (159),
588 B16 (160), B16 (161), B16 (162), B16 (163),
589 B16 (132), B16 (165), B16 (166), B16 (167),
590 B16 (168), B16 (169), B16 (170), B16 (171),
591 B16 (172), B16 (173), B16 (174), B16 (175),
592 B16 (176), B16 (177), B16 (178), B16 (179),
593 B16 (180), B16 (181), B16 (182), B16 (183),
594 B16 (184), B16 (185), B16 (186), B16 (187),
595 B16 (188), B16 (189), B16 (190), B16 (191),
596 B16 (192), B16 (193), B16 (194), B16 (195),
597 B16 (196), B16 (197), B16 (198), B16 (199),
598 B16 (200), B16 (201), B16 (202), B16 (203),
599 B16 (204), B16 (205), B16 (206), B16 (207),
600 B16 (208), B16 (209), B16 (210), B16 (211),
601 B16 (212), B16 (213), B16 (214), B16 (215),
602 B16 (216), B16 (217), B16 (218), B16 (219),
603 B16 (220), B16 (221), B16 (222), B16 (223),
604 B16 (224), B16 (225), B16 (226), B16 (227),
605 B16 (228), B16 (229), B16 (230), B16 (231),
606 B16 (232), B16 (233), B16 (234), B16 (235),
607 B16 (236), B16 (237), B16 (238), B16 (239),
608 B16 (240), B16 (241), B16 (242), B16 (243),
609 B16 (244), B16 (245), B16 (246), B16 (247),
610 B16 (248), B16 (249), B16 (250), B16 (251),
611 B16 (252), B16 (253), B16 (254), B16 (255)
612 };
613
614 static bool
isubase16(unsigned char ch)615 isubase16 (unsigned char ch)
616 {
617 return ch < sizeof base16_to_int && 0 <= base16_to_int[ch];
618 }
619
620 static int
base16_length(int len)621 base16_length (int len)
622 {
623 return len * 2;
624 }
625
626
627 static void
base16_encode(char const * restrict in,idx_t inlen,char * restrict out,idx_t outlen)628 base16_encode (char const *restrict in, idx_t inlen,
629 char *restrict out, idx_t outlen)
630 {
631 static const char base16[16] = "0123456789ABCDEF";
632
633 while (inlen--)
634 {
635 unsigned char c = *in;
636 *out++ = base16[c >> 4];
637 *out++ = base16[c & 0x0F];
638 ++in;
639 }
640 }
641
642
643 static void
base16_decode_ctx_init(struct base_decode_context * ctx)644 base16_decode_ctx_init (struct base_decode_context *ctx)
645 {
646 init_inbuf (ctx);
647 ctx->ctx.base16.nibble = -1;
648 ctx->i = 1;
649 }
650
651
652 static bool
base16_decode_ctx(struct base_decode_context * ctx,char const * restrict in,idx_t inlen,char * restrict out,idx_t * outlen)653 base16_decode_ctx (struct base_decode_context *ctx,
654 char const *restrict in, idx_t inlen,
655 char *restrict out, idx_t *outlen)
656 {
657 bool ignore_lines = true; /* for now, always ignore them */
658 char *out0 = out;
659 signed char nibble = ctx->ctx.base16.nibble;
660
661 /* inlen==0 is request to flush output.
662 if there is a dangling high nibble - we are missing the low nibble,
663 so return false - indicating an invalid input. */
664 if (inlen == 0)
665 {
666 *outlen = 0;
667 return nibble < 0;
668 }
669
670 while (inlen--)
671 {
672 unsigned char c = *in++;
673 if (ignore_lines && c == '\n')
674 continue;
675
676 if (sizeof base16_to_int <= c || base16_to_int[c] < 0)
677 {
678 *outlen = out - out0;
679 return false; /* garbage - return false */
680 }
681
682 if (nibble < 0)
683 nibble = base16_to_int[c];
684 else
685 {
686 /* have both nibbles, write octet */
687 *out++ = (nibble << 4) + base16_to_int[c];
688 nibble = -1;
689 }
690 }
691
692 ctx->ctx.base16.nibble = nibble;
693 *outlen = out - out0;
694 return true;
695 }
696
697
698
699
700 static int
z85_length(int len)701 z85_length (int len)
702 {
703 /* Z85 does not allow padding, so no need to round to highest integer. */
704 int outlen = (len * 5) / 4;
705 return outlen;
706 }
707
708 static bool
isuz85(unsigned char ch)709 isuz85 (unsigned char ch)
710 {
711 return c_isalnum (ch) || strchr (".-:+=^!/*?&<>()[]{}@%$#", ch) != nullptr;
712 }
713
714 static char const z85_encoding[85] =
715 "0123456789"
716 "abcdefghijklmnopqrstuvwxyz"
717 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
718 ".-:+=^!/*?&<>()[]{}@%$#";
719
720 static void
z85_encode(char const * restrict in,idx_t inlen,char * restrict out,idx_t outlen)721 z85_encode (char const *restrict in, idx_t inlen,
722 char *restrict out, idx_t outlen)
723 {
724 int i = 0;
725 unsigned char quad[4];
726 idx_t outidx = 0;
727
728 while (true)
729 {
730 if (inlen == 0)
731 {
732 /* no more input, exactly on 4 octet boundary. */
733 if (i == 0)
734 return;
735
736 /* currently, there's no way to return an error in encoding. */
737 error (EXIT_FAILURE, 0,
738 _("invalid input (length must be multiple of 4 characters)"));
739 }
740 else
741 {
742 quad[i++] = *in++;
743 --inlen;
744 }
745
746 /* Got a quad, encode it */
747 if (i == 4)
748 {
749 int_fast64_t val = quad[0];
750 val = (val << 24) + (quad[1] << 16) + (quad[2] << 8) + quad[3];
751
752 for (int j = 4; j >= 0; --j)
753 {
754 int c = val % 85;
755 val /= 85;
756
757 /* NOTE: if there is padding (which is trimmed by z85
758 before outputting the result), the output buffer 'out'
759 might not include enough allocated bytes for the padding,
760 so don't store them. */
761 if (outidx + j < outlen)
762 out[j] = z85_encoding[c];
763 }
764 out += 5;
765 outidx += 5;
766 i = 0;
767 }
768 }
769 }
770
771 static void
z85_decode_ctx_init(struct base_decode_context * ctx)772 z85_decode_ctx_init (struct base_decode_context *ctx)
773 {
774 init_inbuf (ctx);
775 ctx->ctx.z85.i = 0;
776 ctx->i = 1;
777 }
778
779
780 # define Z85_LO_CTX_TO_32BIT_VAL(ctx) \
781 (((ctx)->ctx.z85.octets[1] * 85 * 85 * 85) + \
782 ((ctx)->ctx.z85.octets[2] * 85 * 85) + \
783 ((ctx)->ctx.z85.octets[3] * 85) + \
784 ((ctx)->ctx.z85.octets[4]))
785
786
787 # define Z85_HI_CTX_TO_32BIT_VAL(ctx) \
788 ((int_fast64_t) (ctx)->ctx.z85.octets[0] * 85 * 85 * 85 * 85 )
789
790 /*
791 0 - 9: 0 1 2 3 4 5 6 7 8 9
792 10 - 19: a b c d e f g h i j
793 20 - 29: k l m n o p q r s t
794 30 - 39: u v w x y z A B C D
795 40 - 49: E F G H I J K L M N
796 50 - 59: O P Q R S T U V W X
797 60 - 69: Y Z . - : + = ^ ! / #dummy comment to workaround syntax-check
798 70 - 79: * ? & < > ( ) [ ] {
799 80 - 84: } @ % $ #
800 */
801 static signed char const z85_decoding[93] = {
802 68, -1, 84, 83, 82, 72, -1, /* ! " # $ % & ' */
803 75, 76, 70, 65, -1, 63, 62, 69, /* ( ) * + , - . / */
804 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, /* '0' to '9' */
805 64, -1, 73, 66, 74, 71, 81, /* : ; < = > ? @ */
806 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, /* 'A' to 'J' */
807 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, /* 'K' to 'T' */
808 56, 57, 58, 59, 60, 61, /* 'U' to 'Z' */
809 77, -1, 78, 67, -1, -1, /* [ \ ] ^ _ ` */
810 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, /* 'a' to 'j' */
811 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, /* 'k' to 't' */
812 30, 31, 32, 33, 34, 35, /* 'u' to 'z' */
813 79, -1, 80 /* { | } */
814 };
815
816 static bool
z85_decode_ctx(struct base_decode_context * ctx,char const * restrict in,idx_t inlen,char * restrict out,idx_t * outlen)817 z85_decode_ctx (struct base_decode_context *ctx,
818 char const *restrict in, idx_t inlen,
819 char *restrict out, idx_t *outlen)
820 {
821 bool ignore_lines = true; /* for now, always ignore them */
822
823 *outlen = 0;
824
825 /* inlen==0 is request to flush output.
826 if there are dangling values - we are missing entries,
827 so return false - indicating an invalid input. */
828 if (inlen == 0)
829 {
830 if (ctx->ctx.z85.i > 0)
831 {
832 /* Z85 variant does not allow padding - input must
833 be a multiple of 5 - so return error. */
834 return false;
835 }
836 return true;
837 }
838
839 while (inlen--)
840 {
841 if (ignore_lines && *in == '\n')
842 {
843 ++in;
844 continue;
845 }
846
847 /* z85 decoding */
848 unsigned char c = *in;
849
850 if (c >= 33 && c <= 125)
851 {
852 signed char ch = z85_decoding[c - 33];
853 if (ch < 0)
854 return false; /* garbage - return false */
855 c = ch;
856 }
857 else
858 return false; /* garbage - return false */
859
860 ++in;
861
862 ctx->ctx.z85.octets[ctx->ctx.z85.i++] = c;
863 if (ctx->ctx.z85.i == 5)
864 {
865 /* decode the lowest 4 octets, then check for overflows. */
866 int_fast64_t val = Z85_LO_CTX_TO_32BIT_VAL (ctx);
867
868 /* The Z85 spec and the reference implementation say nothing
869 about overflows. To be on the safe side, reject them. */
870
871 val += Z85_HI_CTX_TO_32BIT_VAL (ctx);
872 if ((val >> 24) & ~0xFF)
873 return false;
874
875 *out++ = val >> 24;
876 *out++ = (val >> 16) & 0xFF;
877 *out++ = (val >> 8) & 0xFF;
878 *out++ = val & 0xFF;
879
880 *outlen += 4;
881
882 ctx->ctx.z85.i = 0;
883 }
884 }
885 ctx->i = ctx->ctx.z85.i;
886 return true;
887 }
888
889
890 inline static bool
isubase2(unsigned char ch)891 isubase2 (unsigned char ch)
892 {
893 return ch == '0' || ch == '1';
894 }
895
896 static int
base2_length(int len)897 base2_length (int len)
898 {
899 return len * 8;
900 }
901
902
903 inline static void
base2msbf_encode(char const * restrict in,idx_t inlen,char * restrict out,idx_t outlen)904 base2msbf_encode (char const *restrict in, idx_t inlen,
905 char *restrict out, idx_t outlen)
906 {
907 while (inlen--)
908 {
909 unsigned char c = *in;
910 for (int i = 0; i < 8; i++)
911 {
912 *out++ = c & 0x80 ? '1' : '0';
913 c <<= 1;
914 }
915 outlen -= 8;
916 ++in;
917 }
918 }
919
920 inline static void
base2lsbf_encode(char const * restrict in,idx_t inlen,char * restrict out,idx_t outlen)921 base2lsbf_encode (char const *restrict in, idx_t inlen,
922 char *restrict out, idx_t outlen)
923 {
924 while (inlen--)
925 {
926 unsigned char c = *in;
927 for (int i = 0; i < 8; i++)
928 {
929 *out++ = c & 0x01 ? '1' : '0';
930 c >>= 1;
931 }
932 outlen -= 8;
933 ++in;
934 }
935 }
936
937
938 static void
base2_decode_ctx_init(struct base_decode_context * ctx)939 base2_decode_ctx_init (struct base_decode_context *ctx)
940 {
941 init_inbuf (ctx);
942 ctx->ctx.base2.octet = 0;
943 ctx->i = 0;
944 }
945
946
947 static bool
base2lsbf_decode_ctx(struct base_decode_context * ctx,char const * restrict in,idx_t inlen,char * restrict out,idx_t * outlen)948 base2lsbf_decode_ctx (struct base_decode_context *ctx,
949 char const *restrict in, idx_t inlen,
950 char *restrict out, idx_t *outlen)
951 {
952 bool ignore_lines = true; /* for now, always ignore them */
953
954 *outlen = 0;
955
956 /* inlen==0 is request to flush output.
957 if there is a dangling bit - we are missing some bits,
958 so return false - indicating an invalid input. */
959 if (inlen == 0)
960 return ctx->i == 0;
961
962 while (inlen--)
963 {
964 if (ignore_lines && *in == '\n')
965 {
966 ++in;
967 continue;
968 }
969
970 if (!isubase2 (*in))
971 return false;
972
973 bool bit = (*in == '1');
974 ctx->ctx.base2.octet |= bit << ctx->i;
975 ++ctx->i;
976
977 if (ctx->i == 8)
978 {
979 *out++ = ctx->ctx.base2.octet;
980 ctx->ctx.base2.octet = 0;
981 ++*outlen;
982 ctx->i = 0;
983 }
984
985 ++in;
986 }
987
988 return true;
989 }
990
991 static bool
base2msbf_decode_ctx(struct base_decode_context * ctx,char const * restrict in,idx_t inlen,char * restrict out,idx_t * outlen)992 base2msbf_decode_ctx (struct base_decode_context *ctx,
993 char const *restrict in, idx_t inlen,
994 char *restrict out, idx_t *outlen)
995 {
996 bool ignore_lines = true; /* for now, always ignore them */
997
998 *outlen = 0;
999
1000 /* inlen==0 is request to flush output.
1001 if there is a dangling bit - we are missing some bits,
1002 so return false - indicating an invalid input. */
1003 if (inlen == 0)
1004 return ctx->i == 0;
1005
1006 while (inlen--)
1007 {
1008 if (ignore_lines && *in == '\n')
1009 {
1010 ++in;
1011 continue;
1012 }
1013
1014 if (!isubase2 (*in))
1015 return false;
1016
1017 bool bit = (*in == '1');
1018 if (ctx->i == 0)
1019 ctx->i = 8;
1020 --ctx->i;
1021 ctx->ctx.base2.octet |= bit << ctx->i;
1022
1023 if (ctx->i == 0)
1024 {
1025 *out++ = ctx->ctx.base2.octet;
1026 ctx->ctx.base2.octet = 0;
1027 ++*outlen;
1028 ctx->i = 0;
1029 }
1030
1031 ++in;
1032 }
1033
1034 return true;
1035 }
1036
1037 #endif /* BASE_TYPE == 42, i.e., "basenc"*/
1038
1039
1040
1041 static void
wrap_write(char const * buffer,idx_t len,idx_t wrap_column,idx_t * current_column,FILE * out)1042 wrap_write (char const *buffer, idx_t len,
1043 idx_t wrap_column, idx_t *current_column, FILE *out)
1044 {
1045 if (wrap_column == 0)
1046 {
1047 /* Simple write. */
1048 if (fwrite (buffer, 1, len, stdout) < len)
1049 write_error ();
1050 }
1051 else
1052 for (idx_t written = 0; written < len; )
1053 {
1054 idx_t to_write = MIN (wrap_column - *current_column, len - written);
1055
1056 if (to_write == 0)
1057 {
1058 if (fputc ('\n', out) == EOF)
1059 write_error ();
1060 *current_column = 0;
1061 }
1062 else
1063 {
1064 if (fwrite (buffer + written, 1, to_write, stdout) < to_write)
1065 write_error ();
1066 *current_column += to_write;
1067 written += to_write;
1068 }
1069 }
1070 }
1071
1072 static _Noreturn void
finish_and_exit(FILE * in,char const * infile)1073 finish_and_exit (FILE *in, char const *infile)
1074 {
1075 if (fclose (in) != 0)
1076 {
1077 if (STREQ (infile, "-"))
1078 error (EXIT_FAILURE, errno, _("closing standard input"));
1079 else
1080 error (EXIT_FAILURE, errno, "%s", quotef (infile));
1081 }
1082
1083 exit (EXIT_SUCCESS);
1084 }
1085
1086 static _Noreturn void
do_encode(FILE * in,char const * infile,FILE * out,idx_t wrap_column)1087 do_encode (FILE *in, char const *infile, FILE *out, idx_t wrap_column)
1088 {
1089 idx_t current_column = 0;
1090 char *inbuf, *outbuf;
1091 idx_t sum;
1092
1093 inbuf = xmalloc (ENC_BLOCKSIZE);
1094 outbuf = xmalloc (BASE_LENGTH (ENC_BLOCKSIZE));
1095
1096 do
1097 {
1098 idx_t n;
1099
1100 sum = 0;
1101 do
1102 {
1103 n = fread (inbuf + sum, 1, ENC_BLOCKSIZE - sum, in);
1104 sum += n;
1105 }
1106 while (!feof (in) && !ferror (in) && sum < ENC_BLOCKSIZE);
1107
1108 if (sum > 0)
1109 {
1110 /* Process input one block at a time. Note that ENC_BLOCKSIZE
1111 is sized so that no pad chars will appear in output. */
1112 base_encode (inbuf, sum, outbuf, BASE_LENGTH (sum));
1113
1114 wrap_write (outbuf, BASE_LENGTH (sum), wrap_column,
1115 ¤t_column, out);
1116 }
1117 }
1118 while (!feof (in) && !ferror (in) && sum == ENC_BLOCKSIZE);
1119
1120 /* When wrapping, terminate last line. */
1121 if (wrap_column && current_column > 0 && fputc ('\n', out) == EOF)
1122 write_error ();
1123
1124 if (ferror (in))
1125 error (EXIT_FAILURE, errno, _("read error"));
1126
1127 finish_and_exit (in, infile);
1128 }
1129
1130 static _Noreturn void
do_decode(FILE * in,char const * infile,FILE * out,bool ignore_garbage)1131 do_decode (FILE *in, char const *infile, FILE *out, bool ignore_garbage)
1132 {
1133 char *inbuf, *outbuf;
1134 idx_t sum;
1135 struct base_decode_context ctx;
1136
1137 char padbuf[8] = "========";
1138 inbuf = xmalloc (BASE_LENGTH (DEC_BLOCKSIZE));
1139 outbuf = xmalloc (DEC_BLOCKSIZE);
1140
1141 #if BASE_TYPE == 42
1142 ctx.inbuf = nullptr;
1143 #endif
1144 base_decode_ctx_init (&ctx);
1145
1146 do
1147 {
1148 bool ok;
1149
1150 sum = 0;
1151 do
1152 {
1153 idx_t n = fread (inbuf + sum,
1154 1, BASE_LENGTH (DEC_BLOCKSIZE) - sum, in);
1155
1156 if (ignore_garbage)
1157 {
1158 for (idx_t i = 0; n > 0 && i < n;)
1159 {
1160 if (isubase (inbuf[sum + i]) || inbuf[sum + i] == '=')
1161 i++;
1162 else
1163 memmove (inbuf + sum + i, inbuf + sum + i + 1, --n - i);
1164 }
1165 }
1166
1167 sum += n;
1168
1169 if (ferror (in))
1170 error (EXIT_FAILURE, errno, _("read error"));
1171 }
1172 while (sum < BASE_LENGTH (DEC_BLOCKSIZE) && !feof (in));
1173
1174 /* The following "loop" is usually iterated just once.
1175 However, when it processes the final input buffer, we want
1176 to iterate it one additional time, but with an indicator
1177 telling it to flush what is in CTX. */
1178 for (int k = 0; k < 1 + !!feof (in); k++)
1179 {
1180 if (k == 1)
1181 {
1182 if (ctx.i == 0)
1183 break;
1184
1185 /* auto pad input (at eof). */
1186 idx_t auto_padding = REQUIRED_PADDING (ctx.i);
1187 if (auto_padding && (sum == 0 || inbuf[sum - 1] != '='))
1188 {
1189 affirm (auto_padding <= sizeof (padbuf));
1190 IF_LINT (free (inbuf));
1191 sum = auto_padding;
1192 inbuf = padbuf;
1193 }
1194 else
1195 sum = 0; /* process ctx buffer only */
1196 }
1197 idx_t n = DEC_BLOCKSIZE;
1198 ok = base_decode_ctx (&ctx, inbuf, sum, outbuf, &n);
1199
1200 if (fwrite (outbuf, 1, n, out) < n)
1201 write_error ();
1202
1203 if (!ok)
1204 error (EXIT_FAILURE, 0, _("invalid input"));
1205 }
1206 }
1207 while (!feof (in));
1208
1209 finish_and_exit (in, infile);
1210 }
1211
1212 int
main(int argc,char ** argv)1213 main (int argc, char **argv)
1214 {
1215 int opt;
1216 FILE *input_fh;
1217 char const *infile;
1218
1219 /* True if --decode has been given and we should decode data. */
1220 bool decode = false;
1221 /* True if we should ignore non-base-alphabetic characters. */
1222 bool ignore_garbage = false;
1223 /* Wrap encoded data around the 76th column, by default. */
1224 idx_t wrap_column = 76;
1225
1226 #if BASE_TYPE == 42
1227 int base_type = 0;
1228 #endif
1229
1230 initialize_main (&argc, &argv);
1231 set_program_name (argv[0]);
1232 setlocale (LC_ALL, "");
1233 bindtextdomain (PACKAGE, LOCALEDIR);
1234 textdomain (PACKAGE);
1235
1236 atexit (close_stdout);
1237
1238 while ((opt = getopt_long (argc, argv, "diw:", long_options, nullptr)) != -1)
1239 switch (opt)
1240 {
1241 case 'd':
1242 decode = true;
1243 break;
1244
1245 case 'w':
1246 {
1247 intmax_t w;
1248 strtol_error s_err = xstrtoimax (optarg, nullptr, 10, &w, "");
1249 if (LONGINT_OVERFLOW < s_err || w < 0)
1250 error (EXIT_FAILURE, 0, "%s: %s",
1251 _("invalid wrap size"), quote (optarg));
1252 wrap_column = s_err == LONGINT_OVERFLOW || IDX_MAX < w ? 0 : w;
1253 }
1254 break;
1255
1256 case 'i':
1257 ignore_garbage = true;
1258 break;
1259
1260 #if BASE_TYPE == 42
1261 case BASE64_OPTION:
1262 case BASE64URL_OPTION:
1263 case BASE32_OPTION:
1264 case BASE32HEX_OPTION:
1265 case BASE16_OPTION:
1266 case BASE2MSBF_OPTION:
1267 case BASE2LSBF_OPTION:
1268 case Z85_OPTION:
1269 base_type = opt;
1270 break;
1271 #endif
1272
1273 case_GETOPT_HELP_CHAR;
1274
1275 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
1276
1277 default:
1278 usage (EXIT_FAILURE);
1279 break;
1280 }
1281
1282 #if BASE_TYPE == 42
1283 switch (base_type)
1284 {
1285 case BASE64_OPTION:
1286 base_length = base64_length_wrapper;
1287 required_padding = base64_required_padding;
1288 isubase = isubase64;
1289 base_encode = base64_encode;
1290 base_decode_ctx_init = base64_decode_ctx_init_wrapper;
1291 base_decode_ctx = base64_decode_ctx_wrapper;
1292 break;
1293
1294 case BASE64URL_OPTION:
1295 base_length = base64_length_wrapper;
1296 required_padding = base64_required_padding;
1297 isubase = isubase64url;
1298 base_encode = base64url_encode;
1299 base_decode_ctx_init = base64url_decode_ctx_init_wrapper;
1300 base_decode_ctx = base64url_decode_ctx_wrapper;
1301 break;
1302
1303 case BASE32_OPTION:
1304 base_length = base32_length_wrapper;
1305 required_padding = base32_required_padding;
1306 isubase = isubase32;
1307 base_encode = base32_encode;
1308 base_decode_ctx_init = base32_decode_ctx_init_wrapper;
1309 base_decode_ctx = base32_decode_ctx_wrapper;
1310 break;
1311
1312 case BASE32HEX_OPTION:
1313 base_length = base32_length_wrapper;
1314 required_padding = base32_required_padding;
1315 isubase = isubase32hex;
1316 base_encode = base32hex_encode;
1317 base_decode_ctx_init = base32hex_decode_ctx_init_wrapper;
1318 base_decode_ctx = base32hex_decode_ctx_wrapper;
1319 break;
1320
1321 case BASE16_OPTION:
1322 base_length = base16_length;
1323 required_padding = no_required_padding;
1324 isubase = isubase16;
1325 base_encode = base16_encode;
1326 base_decode_ctx_init = base16_decode_ctx_init;
1327 base_decode_ctx = base16_decode_ctx;
1328 break;
1329
1330 case BASE2MSBF_OPTION:
1331 base_length = base2_length;
1332 required_padding = no_required_padding;
1333 isubase = isubase2;
1334 base_encode = base2msbf_encode;
1335 base_decode_ctx_init = base2_decode_ctx_init;
1336 base_decode_ctx = base2msbf_decode_ctx;
1337 break;
1338
1339 case BASE2LSBF_OPTION:
1340 base_length = base2_length;
1341 required_padding = no_required_padding;
1342 isubase = isubase2;
1343 base_encode = base2lsbf_encode;
1344 base_decode_ctx_init = base2_decode_ctx_init;
1345 base_decode_ctx = base2lsbf_decode_ctx;
1346 break;
1347
1348 case Z85_OPTION:
1349 base_length = z85_length;
1350 required_padding = no_required_padding;
1351 isubase = isuz85;
1352 base_encode = z85_encode;
1353 base_decode_ctx_init = z85_decode_ctx_init;
1354 base_decode_ctx = z85_decode_ctx;
1355 break;
1356
1357 default:
1358 error (0, 0, _("missing encoding type"));
1359 usage (EXIT_FAILURE);
1360 }
1361 #endif
1362
1363 if (argc - optind > 1)
1364 {
1365 error (0, 0, _("extra operand %s"), quote (argv[optind + 1]));
1366 usage (EXIT_FAILURE);
1367 }
1368
1369 if (optind < argc)
1370 infile = argv[optind];
1371 else
1372 infile = "-";
1373
1374 if (STREQ (infile, "-"))
1375 {
1376 xset_binary_mode (STDIN_FILENO, O_BINARY);
1377 input_fh = stdin;
1378 }
1379 else
1380 {
1381 input_fh = fopen (infile, "rb");
1382 if (input_fh == nullptr)
1383 error (EXIT_FAILURE, errno, "%s", quotef (infile));
1384 }
1385
1386 fadvise (input_fh, FADVISE_SEQUENTIAL);
1387
1388 if (decode)
1389 do_decode (input_fh, infile, stdout, ignore_garbage);
1390 else
1391 do_encode (input_fh, infile, stdout, wrap_column);
1392 }
1393