Pensamento por Reflexão e Base 64

À primeira vista, pode parecer que as perguntas “para quê isso serve?” e “por quê isso existe?” têm o mesmo significado, mas, pelo menos pra mim, elas são indagações bem diferentes. Consideremos, por exemplo, o sistema de codificação Base 64 (baseado, obviamente, no sistema numérico de base 64).

“Para quê o sistema de codificação Base 64 serve?”. Essa pergunta é um exemplo do que eu chamo de linha de pensamento objetiva, e a sua resposta, portanto, é a seguinte:

“É um sistema de codificação baseado no sistema numérico de base 64 que visa representar dados binários em formato texto utilizando os caracteres da tabela ASCII mais comuns entre diversos sistemas”.

“Por quê o sistema de codificação Base 64 existe?”. Já essa pergunta é um exemplo do que eu chamo de linha de pensamento por reflexão, e, para mim, é aí que todas as coisas começam a ficar interessantes…

Imagine, por um momento, que você nunca ouviu falar no esquema de codificação em Base 64, e que você se encontra na mesma situação na qual eu me encontrava há 4 anos: Eu precisava desenvolver um controle ActiveX para rodar embutido em uma página web, que se comunicaria com um digitalizador de mesa (scanner) e enviaria os dados binários das imagens digitalizadas de volta para o servidor, através de um post-back ou coisa parecida.

O grande problema, nesse e em muitos outros casos, era que o meio-de-campo entre o ActiveX, a página e o servidor teria de ser feito com JavaScript. No entanto, como vocês já devem imaginar, não é possível transferir arranjos (arrays) entre JavaScript e ActiveX, o que já nos limita bastante, pois um binário é, basicamente, um arranjo de bytes (Byte[]). Além disso, mesmo que fosse possível transferir tal arranjo de alguma forma do ActiveX para o JavaScript, como seria possível enviá-lo do JavaScript para o servidor? A solução, em ambos os casos, é uma só: representar o binário de uma outra maneira, preferencialmente através de uma string.

O grande problema na representação de um binário em uma string é que a string interpreta os valores ASCII que são armazenados nela. Isto é, se o binário possuir um byte com o valor 10 (dez), a string irá interpretar esse caractere como uma quebra de linha (LF = Line Feed). Se o binário possuir um byte com o valor 0 (zero), a string entenderá como o seu fim. Se o binário possuir um caractere de valor 8 (oito), a string irá interpretar esse valor como um backspace e, de fato, irá sumir com o caractere anterior!

Dessa forma, a maneira mais simples imaginada por mim na época foi representar o valor do byte (que varia de 0 a 255) através do texto simples do valor do byte, isto é: o valor 246 viraria “246”. Alguns problemas surgem imediatamente após a idéia dessa abordagem: como saber se a string “20165” na verdade significa 2, 0 e 165, ou 20 e 16 e 5? Poderíamos separar com algum caractere, por exemplo “2,0,165” ou ainda poderíamos fixar o número de bytes por byte em 3, de maneira que a string ficaria “002000165”. Entretanto, a desvantagem desse método é um tanto óbvia: o tamanho do binário representado desta forma é, simplesmente, multiplicado por 3.

Mas espera aí… de 0 a 255 é um número conhecido em hexadecimal até para quem só trabalha com cores em HTML: 0 = 0x00 e 255 = 0xff. Então eu poderia representar os valores 2, 0 e 165 como simplesmente “0200a5”! Genial! Dessa forma, o tamanho do binário não seria multiplicado por 3, mas apenas por 2! Ainda assim, dá aquele peso no coração ver o nosso arquivo de 5MB se transformar em 10MB de texto hexadecimal. Não é um algoritmo eficiente. Nesse sistema, eu estou precisando de 8 bits (1 byte) para representar apenas 4 bits (1 nibble).

No entanto, quem disse que estamos presos ao sistema hexadecimal (base 16)? De repente podemos utilizar um sistema de base 32, de 0 a 9 e de ‘a’ a ‘x’. Assim eu representaria 5 bits com 8 bits, o que já é um ganho. Aliás, podemos fazer melhor do que isso! Podemos utilizar os caracteres de ‘0’ a ‘9’, de ‘a’ a ‘z’, de ‘A’ a ‘Z’ e mais os caracteres ‘+’ e ‘/’ para conseguir uma base numérica de 64 caracteres e representar 6 bits com 8 bits! É claro que, como somos inteligentes, tomamos o cuidado de escolher os 64 caracteres da tabela ASCII mais comuns entre todos os sistemas digitais, aumentando sensivelmente o suporte potencial à nossa Base 64!

Pronto, é por isso que o sistema de codificação em Base 64 existe 🙂

Esse sistema ainda aumenta o nosso binário em 25% em relação ao seu tamanho original, mas garante que uma grande gama de sistemas, softwares e dispositivos que suportaram inicialmente somente texto, passem a suportar também conteúdo binário. Esse sistema foi amplamente utilizado na época das BBSs, e ainda é bastante utilizado por softwares e protocolos (POP, SMTP, clientes de e-mail, imagens embutidas em e-mail, representação textual de conteúdo criptografado (incluindo senhas, chaves de criptografia, assinaturas digitais, MD5, SHA1, etc), data URIs, binários embutidos em XML, entre outros).

É claro que ainda poderíamos diminuir um pouco a gama de sistemas suportados e utilizar um sistema de codificação em Base 128, por exemplo, utilizando 8 bits para representar 7 bits do binário. No entanto, é um tanto difícil encontrar mais 64 caracteres legíveis na tabela ASCII, principalmente porque essa tabela, originalmente, só utilizava 7 bits para a definição dos caracteres.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s