base64.c (3229B)
- // Collection of Unix tools, comparable to coreutils
- // SPDX-FileCopyrightText: 2017-2023 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
- // SPDX-License-Identifier: MPL-2.0
- #define _POSIX_C_SOURCE 200809L
- #include <assert.h> /* assert */
- #include <errno.h> /* errno */
- #include <fcntl.h> /* open(), O_RDONLY */
- #include <stdint.h> /* uint8_t */
- #include <stdio.h> /* fprintf(), BUFSIZ */
- #include <string.h> /* strerror(), strncmp() */
- #include <unistd.h> /* read(), write(), close(), getopt(), opt* */
- // 64(26+26+10+2)
- static char b64_encmap[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- static size_t c_out = 0;
- // TODO: -w option ; 76 is lowest of all base64 related RFCs
- static size_t wrap_nl = 76;
- static inline uint8_t
- b64_get(uint8_t pos)
- {
- assert(pos <= 64);
- return b64_encmap[pos];
- }
- static void
- b64encode(uint8_t out[4], uint8_t in[3])
- {
- out[0] = b64_get(in[0] >> 2);
- out[1] = b64_get((uint8_t)(((in[0] & 0x03) << 4) | (in[1] >> 4)));
- out[2] = b64_get((uint8_t)(((in[1] & 0x0f) << 2) | (in[2] >> 6)));
- out[3] = b64_get(in[2] & 0x3f);
- }
- static int
- encode(int fd, const char *fdname)
- {
- ssize_t c = 0;
- char ibuf[3];
- while((c = read(fd, ibuf, sizeof(ibuf))) > 0)
- {
- uint8_t obuf[4] = "----";
- ssize_t pad = 0;
- assert(pad >= 0);
- for(; c < 3; pad++, c++)
- {
- ibuf[c] = 0;
- }
- assert(c == 3);
- b64encode(obuf, (uint8_t *)ibuf);
- for(; pad > 0; pad--)
- {
- obuf[4 - pad] = '=';
- }
- if(write(1, (char *)obuf, 4) != 4)
- {
- fprintf(stderr, "base64: Error writing: %s\n", strerror(errno));
- return 1;
- }
- c_out += 4;
- if(wrap_nl != 0 && c_out >= wrap_nl)
- {
- c_out = 0;
- if(write(1, "\n", 1) != 1)
- {
- fprintf(stderr, "base64: Error writing: %s\n", strerror(errno));
- return 1;
- }
- }
- }
- if(c < 0)
- {
- fprintf(stderr, "base64: Error reading ‘%s’: %s\n", fdname, strerror(errno));
- return 1;
- }
- return 0;
- }
- static int
- decode(int fd, const char *fdname)
- {
- return 1;
- }
- int
- main(int argc, char *argv[])
- {
- int (*process)(int, const char *) = &encode;
- int c = 0, ret = 0;
- while((c = getopt(argc, argv, ":d")) != -1)
- {
- switch(c)
- {
- case 'd':
- process = &decode;
- break;
- case ':':
- fprintf(stderr, "base64: Error: Missing operand for option: ‘-%c’\n", optopt);
- return 1;
- case '?':
- fprintf(stderr, "base64: Error: Unrecognised option: ‘-%c’\n", optopt);
- return 1;
- }
- }
- argc -= optind;
- argv += optind;
- if(argc <= 0)
- {
- ret = process(0, "<stdin>");
- goto end;
- }
- for(int argi = 0; argi < argc; argi++)
- {
- if(strncmp(argv[argi], "-", 2) == 0)
- {
- if(process(0, "<stdin>") != 0)
- {
- ret = 1;
- goto end;
- }
- }
- else if(strncmp(argv[argi], "--", 3) == 0)
- {
- continue;
- }
- else
- {
- int fd = open(argv[argi], O_RDONLY);
- if(fd < 0)
- {
- fprintf(stderr, "base64: Error opening ‘%s’: %s\n", argv[argi], strerror(errno));
- ret = 1;
- goto end;
- }
- if(process(fd, argv[argi]) != 0)
- {
- ret = 1;
- goto end;
- }
- if(close(fd) < 0)
- {
- fprintf(stderr, "base64: Error closing ‘%s’: %s\n", argv[argi], strerror(errno));
- ret = 1;
- goto end;
- }
- }
- }
- end:
- if(c_out > 0)
- {
- printf("\n");
- }
- return ret;
- }