Base64 é um protocolo de codificação que usa apenas seis bits, o que significa um conjunto de sessenta e quatro (64) elementos – daí Base64.
A conversão de oito (byte) para seis bits é feita da seguinte forma:
xxxxxx.xx xxxx.xxxx xx.xxxxxxOu ainda:
aaaaaabb bbbbcccc ccddddddOs elementos usados são caracteres simples, começando com as letras maiúsculas,
A (0) a Z (25), então as letras minúsculas, a (26) a z (51), os números, 0 (52) a 9 (61), e os caracteres + (62) e / (63).Na conversão de bytes (8b) para Base64 (6b), cada três bytes é convertido em quatro dígitos, então um código Base64 é sempre pensado em grupos de quatro. Se o tamanho de um código Base64 não for múltiplo de quatro, caracteres
= são acrescentados ao final até que o tamanho seja múltiplo de quatro.Python
Em Python, Base64 é tão simples que nem tem graça:
>>> print "Kodumaro".encode("base64")
S29kdW1hcm8=
>>> print "S29kdW1hcm8=".decode("base64")
KodumaroLua
Em Lua, é preciso baixar o módulo Mime do LuaSocket:
> require "mime"
> print(mime.b64 "Kodumaro")
S29kdW1hcm8=
> print(mime.unb64 "S29kdW1hcm8=")
KodumaroSmalltalk
Sendo muito sincero sobre o assunto, não sei como fazer conversão de Base64 em Smalltalk. =(
Mas sei que os módulos do Seaside providenciam isso!
Se alguém souber, por favor informe!
[update 2009-11-27]
Sugestão do Hugo:
No Squeak tem isso aqui:(Base64MimeConverter mimeEncode: 'base64' readStream) contents
(Base64MimeConverter mimeDecode: 'S29kdW1hcm8' as: ByteString) contents
E no Pharo tem métodos para strings:'base64' base64Encoded
'S29kdW1hcm8' base64Decoded
A implementação usa as coisas do Squeak:String>>base64Decoded
↑ (Base64MimeConverter mimeDecode: self as: self class)
String>>base64Encoded
↑ (Base64MimeConverter mimeEncode: self readStream) contents
Para outros Smalltalks eu não sei…
Legal né? =)
Muito legal sim, Hugo, valeu!
[/update]
C
Aha! Aqui começa de verdade a brincadeira!
É claro que você pode usar as funcionalidades de Base64 da gLibC, mas descobri que nem todas as versões dela apresentam tais funcionalidades:
#include <glib/gbase64.h>Vamos precisar usar os cabeçalhos
stdlib.h, string.h e sys/types.h. Como também vamos criar um cabeçalho para «compartilhar» algumas funções, ele também será incluído no início de nosso arquivo base64.c:#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include "base64.h"Agora vamos criar um array com todos os possíveis caracteres Base64 em sua ordem natural:
static const char b64all[] =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef"
    "ghijklmnopqrstuvwxyz0123456789+/";Também vamos precisar de três funções locais: uma para obter o índice de um elemento (
_getindex), outra para codificar para Base64 um grupo de três bytes (_encode) e mais uma para decodificar um grupo de quatro elementos Base64 (_decode):int _decode(u_int8_t *, const u_int8_t *);
void _encode(u_int8_t *, const u_int8_t *, int);Não é preciso uma função para
_getindex:#define _getindex(c) (int) (index(b64all, c) - b64all)Repara que, em vez de
char, estamos usando u_int8_t, que é mais conveniente quando queremos lidar com bytes enquanto bytes, não caracteres.A partir daqui, se preferir, organize as funções em ordem alfabética – ou na ordem que quiser.
A primeira função que implementaremos será para codificar uma string C (
const char *) para Base64. Como a string pode não ser bem formada, a função deverá receber também seu tamanho:const char *b64encode(const char *original, int length) {
    // Se o tamanho não for informado, consideramos uma string bem
    // formada
    if (length == 0)
        length = strlen(original);
    // Inteiro com o tamanho do código a ser gerado
    int b64length = ((length + 2) / 3) * 4 + 1;
    // Contadores para percorrer as strings
    int i=0, j=0;
    // Alocando memória para o código
    char *b64 = (char *) malloc(sizeof(char) * b64length);
    memset(b64, 0, b64length);
    while (i < length) {
        // Codifica um grupo de três bytes...
        _encode(
            (u_int8_t *) b64 + j,
            (const u_int8_t *) original + i,
            (length - i)
        );
        // E segue para o próximo grupo
        i += 3;
        j += 4;
    }
    // Retorna o código
    return (const char *) b64;
}A próxima função deve fazer o contrário, converter um código Base64 para uma string. Como a string resultante pode não ser bem formada – pode não ser terminada em carácter nulo ou possuir caracteres nulos no meio –, é preciso uma forma de informar seu tamanho, então ela receberá um ponteiro para um inteiro:
const char *b64decode(const char *b64, int *length) {
    // Inteiro com o tamanho do código
    int b64length = strlen(b64);
    // Se não for múltiplo de quatro, há algo errado
    if (b64length % 4 != 0)
        return NULL;
    // Tamanho máximo da string decifrada
    int prob = (b64length / 4) * 3 + 1;
    // Contadores para percorrer as strings
    int i=0, j=0;
    // Alocando memória para o resultado
    char *s = (char *) malloc(sizeof(char) * prob);
    while (j < b64length) {
        // Decifra um grupo de quatro elementos
        // e conta o resultado
        i += _decode(
            (u_int8_t *) s + i,
            (const u_int8_t *) b64 + j
        );
        // Segue para o próximo grupo
        j += 4;
    }
    // Se foi fornecido um inteiro para contagem, informa o tamanho
    if (length != NULL)
        *length = i;
    // Retorna a string decifrada
    return (const char *) s;
}Agora precisamos das funções específica para as conversões.
Primeiro para codificar:
void _encode(u_int8_t *dest, const u_int8_t *src, int len) {
    // Menor que 1, nada a fazer
    if (len < 1)
        return;
    // Dados a serem retornados
    int aux[] = { 0, 0, 0, 0 };
    // Primeiro elemento: os 6 bits mais significativos do primeiro
    // byte
    aux[0] = src[0] >> 2;
    // Segundo elemento: os 2 bits menos significativos do primeiro e
    // os quatro bits mais significativos do segundo byte
    aux[1] = (src[0] & 0x03) << 4;
    if (len > 1) {
        // SE houver um segundo...
        aux [1] |= (src[1] & 0xf0) >> 4;
        // Terceiro elemento: os quatro bits menos significativos do
        // segundo e os dois mais significativos do terceiro byte
        aux [2] = (src[1] & 0x0f) << 2;
        if (len > 2) {
            // Se houver um terceiro...
            aux[2] |= src[2] >> 6;
            // Quarto elemento: os seis bits menos significatos do
            // terceiro byte
            aux[3] = src[2] & 0x3f;
        }
    }
    // Codifica agora os valores numéricos para string
    dest[0] = b64all[aux[0]];
    dest[1] = b64all[aux[1]];
    dest[2] = '=';
    dest[3] = '=';
    if (len > 1) {
        dest[2] = b64all[aux[2]];
        if (len > 2)
            dest[3] = b64all[aux[3]];
    }
}
int _decode(u_int8_t *dest, const u_int8_t *src) {
    // Representação numérica do código
    int aux[] = { 0, 0, 0, 0 };
    // Contador
    int i, c = 1;
    // Converte código para valores numéricos
    for (i = 0; i < 4; ++i)
        aux[i] = _getindex(src[i]);
    // Primeiro byte: primeiro elemento seguido dos quatro bits mais
    // significativos do segundo
    dest[0] = (u_int8_t) (aux[0] << 2) | ((aux[1] & 0x30) >> 4);
    // Zera os bytes seguintes
    dest[1] = '\0';
    dest[2] = '\0';
    if (aux[2] != -1) {
        // Se houver um terceiro elemento...
        ++c;
        // Segundo byte: quatro bits menos significativos do segundo
        // elemento seguidos pelos quatro bits mais significativos do
        // terceiro
        dest[1] = (u_int8_t) ((aux[1] & 0x0f) << 4) | (aux[2] >> 2);
        if (aux[3] != -1) {
            // Se houver um quarto elemento...
            ++c;
            // Terceiro byte: dois bits menos significativos do
            // terceiro elemento seguidos pelo quarto elemento
            dest[2] = (u_int8_t)
              ((aux[2] & 0x03) << 6) |
              aux[3];
        }
    }
    // Retorna o tamanho da string
    return c;
}Cabeçalho
Por último criamos o cabeçalho
base64.h, tornando públicas as duas funções de codificação e decodificação:#ifndef _BASE64_H
#define _BASE64_H
const char *b64decode(const char *, int *);
const char *b64encode(const char *, int);
#endifConclusão
Mesmo que ninguém vá implementar uma biblioteca de conversão Base64, espero que este artigo sirva para ajudar a entender melhor do que se trata Base64.
Se quiser acrescentar algum açucar sintático, coloque em
base64.c:#ifdef C_PLUS_PLUS
const char *b64decode(const char *b64, int &length) {
    return b64decode(b64, &length);
}
#endifE mude o conteúdo de
base64.h para:#ifndef _BASE64_H
#define _BASE64_H
#ifdef C_PLUS_PLUS
extern "C" {
#endif
const char *b64decode(const char *, int *);
const char *b64encode(const char *, int);
#ifdef C_PLUS_PLUS
}
const char *b64decode(const char *, int &);
#else
#define _b64decode(s, len) b64decode(s, &len)
#endif
#endif[]'s
Cacilhas, La Batalema
 Escrevi recentemente um 



 CC-BY: Os textos deste blog podem ser reporduzidos contanto que sejam informados autor e origem.