Par une remarquable tendance à la perversité de l'esprit humain, certains protocoles « applicatifs » (SMTP par exemple) ont été conçu avec comme axiome de départ qu'ils ne devraient transporter que du texte, alors qu'il est clair qu'ils n'auraient à transporter que des valeurs numériques binaires, puisqu'un système numérique ne sait finalement faire que cela.
D'ailleurs, le premier besoin qui s'est fait sentir, c'est de pouvoir attacher aux e-mails des fichiers qui sont tout, sauf du texte pur.
Pourquoi le parti-pris du texte ?
A cause des caractères de contrôle ! C'est très pratique de disposer de caractères spéciaux qui permettent, comme leur nom l'indique, de contrôler le flux de données. Avec le codage ASCII, nous avons vu qu'il en existait pas mal, même si nous ne sommes pas entrés dans le détail de leur signification.
De plus, nous n'avons pas parlé du codage des valeurs numériques. Si un nombre entier ne pose pas trop de problèmes (1, 2 octets ou plus, éventuellement, encore que reste à savoir dans quel ordre on va les passer), les nombres réels, codés sous la forme mantisse / exposant sont un réel casse-tête. Un exemple faux mais qui fait comprendre : Le nombre 1 245 389 789 726 986 425 ne va pas s'utiliser ainsi, on va d'abord l'écrire, par exemple sous la forme 1245,389789726986425 10 15. On s'attachera alors à stocker en mémoire ce réel sous une forme approchée en utilisant systématiquement, disons trois octets. Sa partie entière, 1245 dans l'exemple, sera codée sur deux octets et la puissance de 10, 15 dans l'exemple, sur un octet.
Cet exemple n'a pas de réalité, mais le principe est à peu près juste. Suivant les plateformes et les langages de programmation, nous aurons nos réels stockés sur 4, 6 ou 8 octets, avec plus ou moins de précision sur la mantisse, ou plus ou moins d'espace sur la puissance de 10, suivant la nature des calculs à réaliser (aviez-vous pensé que la notion d'infini ne peut être gérée par un calculateur ?). Au final, il est souvent plus simple de communiquer des valeurs numériques à un tiers sous leur forme ASCII (telles qu'on peut les afficher ou les imprimer, avec des symboles d'écriture, donc), plutôt que telles qu'elles sont stockées en mémoire.
La conséquence ?
Ces protocoles ne peuvent pas simplement transférer des données numériques, puisqu'un octet est à priori considéré comme l'image d'un caractère et non comme une donnée numérique en elle même. Ainsi, si vous voulez transférer un fichier qui contient une représentation « bitmap » d'une image, comme un fichier jpeg
, png
ou gif
, par exemple, vous ne pouvez pas considérer que c'est du texte, puisque à priori, chaque octet peut prendre n'importe quelle valeur, y compris celle d'un caractère de contrôle. Vous connaissez beaucoup de pages Web sans aucune image dedans ? Vous n'avez jamais envoyé un e-mail avec une image en pièce jointe ?
La conclusion est qu'il a fallu trouver une astuce pour transporter des données purement numériques sur un protocole qui n'est pas prévu pour ça.
Le jeu va consister maintenant à coder une donnée purement numérique sous une forme alphabétique, elle-même codée sur des valeurs numériques, pour qu'elle puisse être transportée sur un système qui ne connaît que des 0 et des 1.
Tordu, n'est-ce pas ?
Oui, mais comment faire autrement ? Les révolutions, c'est bien, mais on ne peut pas en faire tous les jours, sinon, c'est le chaos permanent. Vous allez voir que les solutions apportées sont certes parfois tordues, mais astucieuses et surtout efficaces.
Comme il est clair, à la lueur de ce que nous avons vu jusqu'ici, que la seule convention qui soit à peu près universellement acceptée et correctement transportée par les protocoles applicatifs est la norme iso-646 (US-ASCII), il faudra trouver des conventions de codage pour convertir un octet en un ensemble de caractères sur 7 bits.
C'est parti pour la grande cuisine.
Ce codage est principalement employé pour transformer un texte écrit avec un codage sur 8 bits en un texte qui ne contiendra que des caractères codables sur 7 bits. Vous allez voir comme c'est simple :
D'abord, il faut savoir sur quel codage 8 bits on va s'appuyer, en général, pour nous, iso-8859-1.
Ensuite, nous allons utiliser un « code d'échappement » (c'est une technique assez courante, nous la rencontrons souvent en informatique). Ici, le caractère d'échappement est le signe =. Ce signe signifie que les deux caractères qui vont le suivre représenteront le code hexadécimal d'un caractère et non le caractère lui-même. Bien entendu, il faudra aussi coder le caractère d'échappement.
Un petit exemple vaudra bien mieux qu'un long discours…
L'expression çà et là sera donc transmise sous la forme =E7=E0 et l=E0
Ainsi, nous transporterons nos données uniquement sous la forme de caractères US-ASCII (7 bits), même s'ils nécessitent 8 bits pour être définis. En effet, les caractères =, E, et 0 ont tous des codes ASCII sur 7 bits.
Astucieux non ?
Bien entendu, il vaut mieux le savoir pour décoder correctement le message. Cette méthode est utilisée principalement pour les e-mails. En voici un exemple :
Return-Path:Notez que l'on parle ici de MIME, en indiquant, la nature du contenu (text/plain), le jeu de caractères utilisé (iso-8859-1) et le mode d'encodage : quoted-printable. Nous y reviendrons plus tard.... From: "Christian Caleca" To: Subject: quoted Date: Tue, 5 Nov 2002 10:51:34 +0100 MIME-Version: 1.0 Content-Type: text/plain; charset= "iso-8859-1" Content-Transfer-Encoding: quoted-printable ... X-Mailer: Microsoft Outlook Express 6.00.2800.1106 X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2800.1106 =E7=E0 et l=E0
Aujourd'hui, la plupart des relais de messagerie utilisent ESMTP, qui est capable de transporter du texte sur 8 bits (ISO8859-1 et même UTF-8). Cependant, ceci n'est possible que dans le corps du message et pas dans l'en-tête. Comme le sujet (Subject:) se trouve dans l'en-tête, il ne faudrait pas écrire de sujets en utilisant autre chose que des codes sur 7 bits. Pour permettre à l'internaute d'user des accents dans les sujets, ceux-ci sont alors encodés en « quoted printable » par les clients de messagerie (MUA), avec des résultats plus ou moins heureux.
Plus généralement, ce codage permettra de passer non seulement du texte codé sur 8 bits, mais aussi tout type de données constituées d'octets. Voyons d'abord avec du texte.
Là aussi, il faudra commencer par indiquer en quel code est écrit le texte initial. Pour nous, toujours iso-8859-1.
Trois caractères de 8 bits (24 bits au total) sont découpés sous la forme de 4 paquets de 6 bits (toujours 24 bits au total). Chaque valeur sur 6 bits, comprise donc entre 0 et 3F en hexadécimal, sera symbolisée par un caractère présent, et avec le même code, dans toutes les versions de code ASCII et EBCDIC. La table d'équivalence est celle qui suit. Remarquez que les caractères choisis sont tous codés sur 7 bits en US-ASCII, mais que la valeur qu'ils représentent n'est pas leur code ASCII
dec | hex | car. | dec | hex | car. | dec | hex | car. | dec | hex | car. | |||
0 | 0 | A | 16 | 10 | Q | 32 | 20 | g | 48 | 30 | w | |||
1 | 1 | B | 17 | 11 | R | 33 | 21 | h | 49 | 31 | x | |||
2 | 2 | C | 18 | 12 | S | 34 | 22 | i | 50 | 32 | y | |||
3 | 3 | D | 19 | 13 | T | 35 | 23 | j | 51 | 33 | z | |||
4 | 4 | E | 20 | 14 | U | 36 | 24 | k | 52 | 34 | 0 | |||
5 | 5 | F | 21 | 15 | V | 37 | 25 | l | 53 | 35 | 1 | |||
6 | 6 | G | 22 | 16 | W | 38 | 26 | m | 54 | 36 | 2 | |||
7 | 7 | H | 23 | 17 | X | 39 | 27 | n | 55 | 37 | 3 | |||
8 | 8 | I | 24 | 18 | Y | 40 | 28 | o | 56 | 38 | 4 | |||
9 | 9 | J | 25 | 19 | Z | 41 | 29 | p | 57 | 39 | 5 | |||
10 | A | K | 26 | 1A | a | 42 | 2A | q | 58 | 3A | 6 | |||
11 | B | L | 27 | 1B | b | 43 | 2B | r | 59 | 3B | 7 | |||
12 | C | M | 28 | 1C | c | 44 | 2C | s | 60 | 3C | 8 | |||
13 | D | N | 29 | 1D | d | 45 | 2D | t | 61 | 3D | 9 | |||
14 | E | O | 30 | 1E | e | 46 | 2E | u | 62 | 3E | + | |||
15 | F | P | 31 | 1F | f | 47 | 2F | v | 63 | 3F | / |
Comme cette explication doit paraître fumeuse à plus d'un (moi-même, plus je la relis, plus je la trouve fumeuse), là encore, prenons un exemple. Soit à coder le texte extrêmement simple : 012
Ce texte est destiné à être écrit avec un codage iso-8859-1.
caractère initial | 0 | 1 | 2 |
Code ASCII hexa | 30 | 31 | 32 |
Code ASCII binaire | 00110000 | 00110001 | 00110010 |
Bien. nous avons donc la suite de 24 bits suivante : 001100000011000100110010. Nous allons maintenant la couper en quatre morceaux de 6 bits :
les valeurs sur 6 bits | 001100 | 000011 | 000100 | 110010 |
Equivalent hexadécimal | 0C | 03 | 04 | 32 |
Caractère équivalent en Base64 | M | D | E | y |
Et voilà. 012 donne, une fois codé en Base 64 MDEy. Constatez comme c'est simple. Constatez surtout que ces caractères seront transcrits en US-ASCII, donc sur 7 bits.
Pour décoder, il suffit de le faire dans l'autre sens.
Refaisons la manip avec un e-mail codé en Base64 :
Return-Path:Et voilà le travail.... From: "Christian Caleca" To: Subject: Base 64 (1) Date: Tue, 5 Nov 2002 11:07:11 +0100 MIME-Version: 1.0 Content-Type: text/plain; charset= "iso-8859-1" Content-Transfer-Encoding: base64 ... X-Mailer: Microsoft Outlook Express 6.00.2800.1106 X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2800.1106 MDEy
Ca, c'est une démo « commerciale », c'est à dire, qui ne montre que ce qui est facile et qui marche bien. Vos messages contiennent tous un nombre de caractères qui est un exact multiple de 3 ?
Dans ce cas (nombre de caractères qui n'est pas un multiple de 3) , le système de codage va « remplir le trou » avec un caractère spécial, qui ne sera pas interprété à l'arrivée. Ce caractère est le signe =
Voyons ce que ça donne si le texte initial ne contient plus que le seul caractère 0.
Au total, on aura MA==
Vérification par l'e-mail :
Return-Path:CQFD.... From: « Christian Caleca » To: Subject: base 64 (3) Date: Tue, 5 Nov 2002 11:18:06 +0100 MIME-Version: 1.0 Content-Type: text/plain; charset= »iso-8859-1 » Content-Transfer-Encoding: base64 ... X-Mailer: Microsoft Outlook Express 6.00.2800.1106 X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2800.1106 MA==
Nous verrons que ce codage base64, qui permet de transformer tout octet en un équivalent ASCII, permettra par exemple de coder des pièces jointes de types divers dans les e-mails.
Bien entendu, d'autres conventions existent, mais n'appartiennent pas aux système MIME. Par exemple UUENCODE, assez proche de Base64, mais antérieur, utilisé sur plateformes Unix.
Un codage propriétaire, créé dans le monde Macintosh pour les mêmes raisons…
Vous le voyez, les astuces ne manquent pas pour utiliser exclusivement de l'ASCII 7 bits dans le transport de n'importe quelle donnée.
En plus du codage des caractères dans des tables de 7 , 8 ou plus, il faut donc ajouter des systèmes qui vont s'efforcer de représenter tout type de donnée sous forme de texte 7 bits.
Ceci nous amène naturellement à parler de MIME…