./ MultiCS.r82 / base64.c
#define CR '\r'
#define LF '\n'
#define CRLF "\r\n"

#define CBASE64_BUFFSZ 32

char base64_chr_table(int index)
{
    char table[] = {
        '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','+','/'};

    return table[index];
}

typedef struct b64_chunk
{
/*
** longeur de la chaine, comme on n'aura besoin d'aller de 0 a 3, on utilise un
** unsigned char plutot qu'un unsigned int pour gagner 3 octets sur un une
** plateforme 32 bits.
*/
    int len;
/*
** Buffers d'encodage et de décodage.
*/
    char enc[4];
    char dec[3];
}B64_CHUNK;


void base64_encoding_process(B64_CHUNK *ptr)
{
    ptr->enc[0] = base64_chr_table((ptr->dec[0] & 0xFC) >> 2);
    ptr->enc[1] = base64_chr_table((((ptr->dec[0] & 0x03) << 4) |
        ((ptr->dec[1] & 0xF0) >> 4)));
    ptr->enc[2] = (ptr->len > 1) ?
        base64_chr_table(((ptr->dec[1] & 0x0F) << 2) |
            ((ptr->dec[2] & 0xC0) >> 6)) :
        '=';
    ptr->enc[3] = (ptr->len > 2) ?
        base64_chr_table(ptr->dec[2] & 0x3F) :
        '=';
}

void base64_decoding_process(B64_CHUNK *ptr)
{
    ptr->dec[0] = ((ptr->enc[0] & 0x3F) << 2) | (((ptr->enc[1]) & 0x30) >> 4);
    ptr->dec[1] = ((ptr->enc[1] & 0x0F) << 4) | (((ptr->enc[2]) & 0x3C) >> 2);
    ptr->dec[2] = ((ptr->enc[2] & 0x0F) << 6) | ((ptr->enc[3]) & 0x3F);
}

/*
** Encodage d'une chaine de caracteres
*/
char * base64_pencode(const char *in, char *out, int linesz)
{
    int i, o, len;
    B64_CHUNK *chunk;
    chunk = malloc(sizeof(*chunk));

    for(i = 0, o = 0, len = 0; in[i];)
    {
        for (chunk->len = 0; chunk->len < 3 && in[i];)
        {
            chunk->dec[chunk->len++] = in[i++];
        }

        base64_encoding_process(chunk);
        if (len >= linesz)
        {
            out[o++] = '\r';
            out[o++] = '\n';
            len = 0;
        }
        for (chunk->len = 0; chunk->len < 4;)
        {
            out[o++] = chunk->enc[chunk->len++];
            len++;
        }
    }
    out[o] = '\0';

    free(chunk);
    return out;
}

/*
** Décodage d'une chaine de caracteres
*/


void base64_chr_real(char *chr)
{
    if (
        *chr >= 0x41 && *chr <= 0x5A)
    {
        *chr -= 0x41;
    }
    else if (*chr >= 0x61 && *chr <= 0x7A)
    {
        *chr -= 0x47;
    }
    else if (*chr >= 0x30 && *chr <= 0x39)
    {
        *chr += 0x04;
    }
    else if (*chr == 0x2B)
    {
        *chr = 0x3E;
    }
    else if (*chr == 0x2F)
    {
        *chr = 0x3F;
    }
    else if (*chr == 0x3D)
    {
        *chr = 64;
    }
    else
    {
        *chr = -1;
    }
}

char * base64_pdecode(const char *in, char *out)
{
    int i, o;
    B64_CHUNK *chunk;

    chunk = malloc(sizeof(*chunk));

    for (i = 0, o = 0; in[i];)
    {
        for (chunk->len = 0; chunk->len < 4 && in[i];)
        {
            chunk->enc[chunk->len] = in[i++];
            
            base64_chr_real(chunk->enc + chunk->len);

            if (chunk->enc[chunk->len] >= 0)
            {
                chunk->len++;
            }
        }

        base64_decoding_process(chunk);

        for (chunk->len = 0; chunk->len < 3 && chunk->dec[chunk->len];)
        {
            out[o++] = chunk->dec[chunk->len++];
        }
    }
    out[o] = '\0';

    free(chunk);
    return out;
}