/* Copyright (c) 2021 Ben Fuller * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * 3. Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #define BUF_SIZE 2097152 const char tbl_base64[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '=' /* termination character */ }; static void usage(const char *name) { fprintf(stderr, "usage: %s [-d] [-w COLS] [FILE]\n", name); } char *base64(unsigned char *i, ssize_t length, unsigned dflg){ if (dflg) return NULL; char *out = malloc(length/3 * 4 + 100); int o = 0; /* index of position in out */ while (length > 0) { unsigned char i1, i2; i1 = i2 = 0; length -= 3; if (length >= -2) { i2 = i[2]; if (length >= -1) i1 = i[1]; } out[o] = tbl_base64[i[0] >> 2]; ++o; out[o] = tbl_base64[((i[0] & 3) << 4) | (i1 >> 4)]; ++o; out[o] = tbl_base64[((i1 & 0xf) << 2) | (i2 >> 6)]; ++o; out[o] = tbl_base64[i2 & 0x3f]; ++o; i += 3; } out[o] = '\0'; while (length < 0){ length++; o--; out[o] = tbl_base64[64]; } return out; } void print_wrapped(char *s, int line_length){ /* printf a string wrapped to line_length chars */ int c = 0; while (1){ if (*s == '\0') break; printf("%c", *s++); c++; if (c == line_length){ c = 0; printf("\n"); } } if (c != 0) printf("\n"); } int main(int argc, char **argv) { int c; int wrap_cols = 76; unsigned dflg = 0; const char *name = argv[0]; while ((c = getopt(argc, argv, "dhw:")) != -1) { switch(c) { case 'd': dflg++; break; case 'w': wrap_cols = atoi(optarg); break; case 'h': usage(name); return 0; case '?': usage(name); return 2; } } /* only work on one file */ if (optind + 1 < argc) { fprintf(stderr, "too many arguments\n"); usage(name); return 2; } int fd; if (optind == argc || *argv[optind] == '-') { /* read from stdin */ fd = STDIN_FILENO; } else { /* open the named file */ if ((fd = open(argv[optind], O_RDONLY)) == -1 ) { perror(argv[optind]); return 1; } } /* read the whole file into *buf */ ssize_t bytes; size_t used = 0, size = 0; unsigned char *buf = NULL, *temp; while (1){ if (used + BUF_SIZE + 1 > size){ size = used + BUF_SIZE + 1; temp = realloc(buf,size); if (temp == NULL) { /* out of memory */ free(buf); return 1; } buf = temp; } if ((bytes = read(fd, buf+used, BUF_SIZE)) <= 0 ) { if (bytes == 0) break; /* read returns 0 when EOF has been reached */ perror("read"); return 1; } used += bytes; } char *output = base64(buf, used, dflg); print_wrapped(output, wrap_cols); if (close(fd) != 0) { perror("close"); return 1; } return 0; }