# UTF-16

UTF-16 est un codage des caractères défini par Unicode, où chaque caractère est codé sur une suite de un ou deux mots de 16 bits.
Le codage était défini dans le rapport technique 17, annexé à la norme Unicode. Depuis, cette annexe est devenue obsolète car UTF-16 fait partie intégrante de la norme Unicode, dans son chapitre 3 Conformance, qui la définit de façon très stricte.
L'UTF-16 ne doit pas être confondu avec l'UCS-2 qui est le codage, plus simple, de chaque caractère sur deux octets. Ces deux normes sont pourtant appelées toutes les deux Unicode, car le codage est le même tant que l'on n'utilise pas les plages entre U+D800 et U+DFFF (en principe réservées) et les plages au-delà U+FFFF (peu utilisées en Occident).

## Usage

L'UTF-16 est en particulier utilisé dans les environnements Windows. Dans ce système, les API dites Unicode utilisent ce standard. Il en va de même du système NTFS.
UTF-16 est le standard de chaînes de caractères utilisé par l'UEFI.

## Description

Le numéro de chaque caractère (son point de code) est donné par la norme ISO/CEI 10646, et repris à l'identique par le standard Unicode. Les points de code qui peuvent être représentés doivent être dans l’intervalle de validité U+0000 à U+10FFFF, et ne doivent pas être affectés à un non-caractère. Tous les caractères possibles dans Unicode possèdent de tels points de code.
Tout point de code qui n’est pas un non-caractère, et dont la valeur peut être codée sur un seul codet de deux octets (16 bits), c’est-à-dire tout point de code U+0000 à U+D7FF et U+E000 à U+FFFD, est stocké sur un seul mot de 16 bits (la plage de non-caractères U+D800 à U+DFFF est donc exclue, c'est-à-dire les points de code dont les 5 bits de poids fort sont 11011).
Dans les autres cas, le caractère est un point de code d’un plan supplémentaire (donc entre U+10000 et U+10FFFD et dont les 16 bits de poids faible ne doivent pas égaler 0xFFFE ou 0xFFFF) ; il est alors stocké sur 2 mots (codets) successifs de 16 bits chacun, dont les valeurs correspondent aux points de code réservés dans les demi-zones d’indirection allouées dans le plan multilingue de base des normes Unicode et ISO/CEI 10646 :
* le premier mot aura les 6 bits de poids fort égaux à 110110 et sera donc compris dans l’intervalle [0xD800 .. 0xDBFF] (ici en numération hexadécimale) ; ce mot contiendra dans ses 10 bits de poids faible les 10 bits de poids fort de la différence (représentée sur 20 bits) entre le point de code à stocker et le premier point de code supplémentaire U+10000 ;
* le second mot aura les 6 bits de poids fort égaux à 110111 et sera donc compris dans l’intervalle [0xDC00 .. 0xDFFF] (ici en numération hexadécimale) ; ce mot contiendra dans ses 10 bits de poids faible les 10 bits de poids faible du point de code à stocker.
Puis suivant le format de stockage des mots de 16 bits dans un flux ordonné d’octets, deux systèmes sont possibles pour le codage final :
Principe du codage UTF-16 en big endian (on représente ici les bits) :
| Numéro du caractère | 00000000 000uuuuu xxxxxxyy yyyyyyyy | 00000000 000uuuuu xxxxxxyy yyyyyyyy | 00000000 000uuuuu xxxxxxyy yyyyyyyy | 00000000 000uuuuu xxxxxxyy yyyyyyyy |
| Codage UTF-16BE (sur 2 octets) | | | xxxxxxyy | yyyyyyyy |
| (seulement si uuuuu = 00000) ||||
| Codage UTF-16BE (sur 4 octets) | 110110ww | wwxxxxxx | 110111yy | yyyyyyyy |
| avec wwww = uuuuu - 1 (si uuuuu > 00000) ||||
Principe du codage UTF-16 en little endian (on représente ici les bits) :
| Numéro du caractère | 00000000 000uuuuu xxxxxxyy yyyyyyyy | 00000000 000uuuuu xxxxxxyy yyyyyyyy | 00000000 000uuuuu xxxxxxyy yyyyyyyy | 00000000 000uuuuu xxxxxxyy yyyyyyyy |
| Codage UTF-16LE (sur 2 octets) | | | yyyyyyyy | xxxxxxyy |
| (seulement si uuuuu = 00000) ||||
| Codage UTF-16LE (sur 4 octets) | wwxxxxxx | 110110ww | yyyyyyyy | 110111yy |
| avec wwww = uuuuu - 1 (si uuuuu > 00000) ||||
L’indication du type de codage utilisé (ordre des octets) peut être implicite pour le protocole utilisé, ou précisé explicitement par ce protocole (en indiquant par exemple les noms réservés "UTF-16BE" ou "UTF-16LE" dans un entête de charset MIME). Si le protocole ne permet pas de spécifier l’ordre des octets, et s’il permet l’une ou l’autre des alternatives, on pourra utiliser le codage UTF-16 du point de code valide U+FEFF comme indicateur en tête du flux de données (car un changement d’ordre de ses octets à la lecture du flux conduira à un point de code U+FFFE, valide dans Unicode mais affecté à un non-caractère et donc interdit dans ce cas dans tout flux UTF-16. Ce point de code ainsi représenté (appelé indicateur d'ordre des octets, byte order mark en anglais, abrégé BOM) ne sera codé qu’au début du flux de données, et permet de savoir comment a été codé le flux :
| 1er octet | 2e octet | Codage effectif |
| 0xFE | 0xFF | big endian |
| 0xFF | 0xFE | little endian |
Si l’une des deux séquences de deux octets chacune est présente en tête de flux, le type de codage en est déduit et la séquence est retirée du flux : elle ne représente aucun caractère du texte stocké dans ce flux de données. Si aucune des deux séquences ne figure en tête du flux de données, la norme Unicode spécifie que le flux doit être décodé en big endian (UTF-16BE).
Ailleurs qu’au début du flux (y compris après un BOM initial), ces séquences ne sont pas reconnues comme codant un BOM et le décodage se poursuit avec un type de codage unique ; donc si ces séquences apparaissent après le début, alors :
* soit le texte contient bien le caractère U+FEFF (espace insécable sans chasse, zero-width non-breaking space en anglais, abrégé ZWNBSP) si le mot de 16 bits est correctement codé dans le bon ordre,
* soit le flux est invalide et ne contient pas de texte conforme aux normes Unicode et ISO/CEI 10646.
De même le flux doit être considéré comme invalide et ne contenant pas de texte conforme à Unicode s’il contient un mot de 16 bits compris entre 0xD800 et 0xDBFF non immédiatement suivi d’un mot compris entre 0xDC00 et 0xDFFF, ou s’il contient un mot de 16 bits entre 0xDC00 et 0xDFFF non immédiatement précédé d’un mot entre 0xD800 et 0xDBFF, ou si le décodage fait apparaître le point de code de tout autre non-caractère.