# Unicode

À esta altura você já pode imaginar a dificuldade que profissionais de computação enfrentam ao trabalhar com diferentes codificações de texto, mas existe um esforço chamado de Unicode mantido pelo Unicode Consortium que compreende várias codificações, que estudaremos a seguir. As *strings* neste formato são comumente chamadas de ***wide strings*** (largas, numa tradução livre).

O Unicode define mais de um milhão de *code points* **únicos***.* Para manter a compatibilidade com a codificação ASCII, os *code points* de 0 a 127 são iguais ao da ASCII e os *code points* de 128 a 255 são iguais aos da *code page* ISO-8859-1 (mas isso pode ser sobreposto por esquemas de codificação como o UTF-8, que veremos mais adiante).

O esforço é cobrir todos os caracteres dos idiomas e para isso, claro, não daria para se limitar a um byte por caractere. Além disso, Unicode não utiliza *code pages* (lembre-se que os *code points* são únicos).

Na teoria é tudo muito belo, mas os problemas aparecem quando pensamos em **como** armazenar caracteres Unicode em arquivos ou na memória do computador. Por exemplo: quantos *bytes* são necessários para cada caractere Unicode? Pois é... o padrão Unicode não especifica isso. Por isso foram inventados **esquemas de codificação** que transforam *code points* Unicode em *bytes*. Veremos os principais agora.

## UTF-8

O UTF (*Unicode Transformation Format*) de 8 *bits* foi desenhado originalmente por Ken Thompson (criador do Unix) e Rob Pike (criador da linguagem Go) para abranger todos os caracteres possíveis nos vários idiomas deste planeta.

Com **1 byte**, o UTF-8 codifica ASCII somente. Os próximos caracteres utilizam **2** ***bytes*** e compreendem não só o alfabeto latino (como na ASCII estendida com *code page* ISO-8859-1) mas também os caracteres gregos, árabes, hebraicos, dentre outros. Já para representar os caracteres de idiomas como o chinês e japonês, **3** ***bytes*** são necessários. Por fim, há os caracteres de antigos manuscritos, símbolos matemáticos e até *emojis,* que utilizam **4** ***bytes***.

Concluímos que os caracteres UTF-8 **variam** de 1 a 4 bytes. Sendo assim, como ficaria o texto "mentebinária" numa sequência de *bytes*? Podemos ver novamente com o Python, mas dessa vez ao invés declarar um objeto do tipo `bytes` com aquele prefixo **`b`**, vamos converter um tipo `str` para `bytes` utilizando o método `encode()`. Isso é necessário porque queremos ver uma string UTF-8 e não ASCII:

```python
>>> 'mentebinária'.encode('utf-8').hex(' ')
'6d 65 6e 74 65 62 69 6e c3 a1 72 69 61'
```

Como dito antes, os *code points* da tabela ASCII são os mesmos em UTF-8, mas o caractere 'á' (que não existe em ASCII puro) utiliza 2 bytes (no caso, C3 A1) para ser representado. Esta é uma *string* UTF-8 válida. Dizemos que seu tamanho é 12 porque ela contém 12 caracteres, mas em *bytes* seu tamanho é 13.

Vamos ver um *emoji* agora:

```python
>>> '💚'.encode('utf-8').hex(' ')
'f0 9f 92 9a'
```

O coração verde, que usamos bastante na Mente Binária, é codificado em quatro *bytes*: f0 9f 92 9a.

O UTF-8 reina na web pois seu padrão variável permite uma significativa economia de *bytes* para grande parte dos textos, mas existem outros esquemas de codificação de *code points* Unicode que vale mencionar para nossos objetivos.

## UTF-16

Também conhecido por UCS-2, este tipo de codificação é frequentemente encontrado em programas compilados para Windows, incluindo os escritos em .NET. É de extrema importância que você o conheça bem.

Representados em UTF-16, os caracteres da tabela ASCII possuem **2 bytes** de tamanho, mesmo que não precisem. O *byte* adicional estará zerado. Vamos entender melhor com a ajuda do Python.

Primeiro, exibimos os *bytes* em hexa equivalentes de cada caractere da string:

```python
>>> b'mente'.hex(' ')
'6d 65 6e 74 65'
```

Até aí nenhuma novidade, mas vejamos como essa string seria codificada em UTF-16:

```python
>>> 'mente'.encode('utf-16').hex(' ')
'ff fe 6d 00 65 00 6e 00 74 00 65 00'
```

A primeira dupla de *bytes* é FF FE, mas de onde ela veio? Esta é a *Byte Order Mark* (BOM) ou Marca de Ordem de *Byte* e define a ordem (ou *endianness*) dos bytes nos *code points*. Se for FF FE como neste caso, os *bytes* estão em *little-endian*, o que significa que o *byte* menos significativo está à esquerda. Em outras palavras, o número 0x0006d será armazenado como 6D 00. Se o BOM fosse FE FF, então esse número seria armazenado como 00 6D.

Também é possível utilizar a codificação UTF-16-LE, que já utiliza *little-endian* por padrão, sem precisar da BOM:

```python
>>> 'mente'.encode('utf-16-le').hex(' ')
'6d 00 65 00 6e 00 74 00 65 00'
```

A codificação UTF-16-LE (lembre-se: sem BOM) é a utilizada pelo Visual Studio no Windows quando tipos `WCHAR` são usados, como nos argumentos das funções `MessageBoxW()` e `CreateFileW()`. Também é a codificação padrão para programas em .NET. Isto é importante de saber pois se você precisar alterar uma string UTF-16-LE durante a engenharia reversa, vai ter que respeitar essas regras.

Além da UTF-16-LE, temos a UTF-16-BE (*Big Endian*), onde os *bytes* estão em *big-endian*, ou seja, na ordem direta, com o *byte* mais significativo à esquerda:

```python
>>> 'mente'.encode('utf-16-be').hex(' ')
'00 6d 00 65 00 6e 00 74 00 65'
```

Além disso, é importante ressaltar que em strings UTF-16 também há a possibilidade de caracteres de quatro *bytes*. Por exemplo, nosso coração verde de novo:

```python
>>> '💚'.encode('utf-16-le').hex(' ')
'3d d8 9a dc'
```

Perceba que os bytes são totalmente diferentes da versão UTF-8 do mesmo caractere. Eu sei, não é simples, mas é o que é.

### Code points da ISO-8859-1 na UTF-16

Os números (*code points*) utilizados pela ISO-8859-1 para seus caracteres são também os números utilizados em strings UTF-16. No Windows, como já falado, o padrão é o UTF-16-LE. Para entender como isso funciona, observe primeiro os *bytes* da string "binária" na codificação ISO-8859-1:

```python
>>> 'binária'.encode('iso-8859-1').hex(' ')
'62 69 6e e1 72 69 61'
```

Perceba que o *byte* referente ao "á" é o E1. Até aí nenhuma novidade. Sabemos que é uma string ASCII estendida que usa a tabela ISO-8859-1, também conhecida por Latin-1. Agora, vejamos como ela fica em UTF-16-LE:

```python
>>> 'binária'.encode('utf-16-le').hex(' ')
'62 00 69 00 6e 00 e1 00 72 00 69 00 61 00'
```

Nesse caso, "binária" é uma string UTF-16-LE sem BOM. Os *bytes* dos caracteres em si coincidem com os da ISO-8859-1. Doido né? Mas vamos em frente!

> Perceba que o "á" em UTF-8 é C3 A1, mas em UTF-16 é E1 (precedido ou sucedido por zero), assim como na *code page* ISO-8859-1.

## UTF-32

Também chamado de UCS-4, este padrão utiliza 4 *bytes* para cada caractere. Ele é o mais simples, mas ocupa mais espaço. Vamos ver como fica a string "mb" em UTF-32 com BOM:

```python
>>> 'mb'.encode('utf-32').hex(' ')
'ff fe 00 00 6d 00 00 00 62 00 00 00'
```

Perceba o BOM obrigatório de quatro *bytes* ao invés de dois.

Agora em UTF-32-LE:

```python
>>> 'mb'.encode('utf-32-le').hex(' ')
'6d 00 00 00 62 00 00 00'
```

E por fim em UTF-32-BE:

```python
>>> 'mb'.encode('utf-32-be').hex(' ')
'00 00 00 6d 00 00 00 62'
```

Perceba que a BOM só é adicionada quando não especificamos o *endianness*.

É importante ressaltar que simplesmente dizer que uma *string* é Unicode não diz exatamente qual codificação ela está utilizando, fato que normalmente depende do sistema operacional, da pessoa que programou, do compilador utilizado, dentre outros fatores. Por exemplo, um programa feito em C no Windows e compilado com Visual Studio, normalmente tem as *wide strings* em UTF-16-LE. Já no Linux, o tamanho do tipo *wchar\_t* é de 32 *bits*, resultando em *strings* UTF-32.

Há muito mais sobre codificação de texto para ser dito, mas isso foge do escopo deste livro. Se desejar se aprofundar no assunto, basta consultar a documentação oficial dos grupos que especificam estes padrões. No entanto, cabe ressaltar que, para a engenharia reversa, a prática de compilar programas e buscar como as *strings* são codificadas é a melhor escola.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://mentebinaria.gitbook.io/engenharia-reversa/03-cadeias-de-texto/unicode.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
