#include<stdio.h>

#define BUFSIZE 48
#define NUMENCDATA 4

static const size_t sixbase = 0b111111;
static const size_t eigbase = 0b11111111;
static const char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

typedef struct _FMS {
    size_t bytes;
    size_t state;
} FMS;

enum State { First = 1, Second = 2, Third = 3, Finish = 4 };
static FMS initState = { 0, First };

void FMS_init(FMS *self) {
    *self = initState;
}

void FMS_stack(FMS *self, char c) {
    size_t stack = (size_t)c;
    switch (self->state) {
        case First:
            self->bytes = (stack << 16);
            self->state = Second;
            break;
        case Second:
            self->bytes = self->bytes | (stack << 8) ;
            self->state = Third;
            break;
        case Third:
            self->bytes = self->bytes | stack;
            self->state = Finish;
            break;
        case Finish:
            fprintf(stderr,"スタックがいっぱいです。\n");
            break;
    }
}

void FMS_stackdata_encode_flush(FMS *self) {
    char res[NUMENCDATA];
    if(self->state == Finish) { 
        for(size_t it = 0; it != NUMENCDATA; ++it) {
            res[it] = table[(self->bytes & (sixbase << (18 - 6 * it))) >> (18 - 6 * it)];
        }
        fwrite(res, sizeof(char), NUMENCDATA, stdout);
        *self = initState;
    }
}

void b64enc(FILE *fp) {
    FMS fms;
    FMS_init(&fms);
    char buf[BUFSIZE];
    size_t nread;
    while((nread = fread(buf, sizeof(char), BUFSIZE, fp)) > 0) {
        for(size_t it = 0; it != BUFSIZE; ++it) {
            FMS_stack(&fms, buf[it]);
            FMS_stackdata_encode_flush(&fms);
        }
        printf("\n");
    }
}

int main(void) {
    FILE *fp;
    if( fopen_s(&fp,"base64s.c", "rb") < 0) {
        fprintf(stderr, "ファイルを開けませんでした!\n");
        return 1;
    }
    b64enc(fp);
    fclose(fp);
    return 0;
}