about summary refs log blame commit diff stats
path: root/base64.c
blob: e0c50ccd86969650e10bfa528087a84c02668f08 (plain) (tree)
1
2

                                














                                                                     
  











                                                                      



                   
                   


                     
                        
 











                                               
                                     
                                                               

 
                                                              

                                           
                                             
                        
                             





                                        

                                       
                                                           
            
                                                           


                                       

               
                  

                       

                                
     
               

 











                                                      
                             

 
                                 
          
                       
                      
                               
                                                    



                       


                                         


                            


                            

         





                                                
           
                                                 
                             
                          
            
                                 


                                                         
         
     

                                       
                  

                                     
              











                                                           



                                                                                 
                      
 
     

                                           
                                     




                         
 


             
/* 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 <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>

#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;

}