Le BOCU-1 est un schéma de transformation du texte, compatible avec le répertoire universel d’Unicode et ISO/CEI 10646, en séquences d’octets. Il tire son nom de l’acronyme anglais de Binary Ordered Compression for Unicode (« compression ordonnée binairement pour Unicode »), qui décrit une méthode brevetée de codage plus générale, et dont BOCU-1 est une des variantes possibles ; cette variante est standardisée de façon très stricte (de façon bien plus limitative que la méthode de codage BOCU qui a d’autres applications que le seul codage du texte) et réutilisable sous cette forme dans des applications libres (sous certaines réserves concernant certaines modifications qui restent interdites sans l’obtention préalable d’une autorisation et d’une licence spécifiques si ces modifications ne sont pas strictement conformes à la spécification de cette seule variante).
Comme UTF-8, BOCU-1 est compatible avec MIME et les formats de fichiers texte usuels, car il laisse les codes de contrôle C0 essentiels (utilisés comme séparateurs de ligne ou de page) ainsi que les blancs (espaces normales et tabulations) codés sous forme d’octets simples qui ne servent pas non plus à représenter d’autres caractères multi-octets. Et comme UTF-8 (mais pas UTF-16 ou SCSU), il conserve au niveau binaire l’ordre de tri des valeurs scalaires des points de code. Cependant BOCU-1 n’est pas utilisable tel quel pour coder les noms de documents et dossiers (dans les systèmes de fichiers), ni dans les URL.
Son intérêt par rapport à UTF-8 (dans son utilisation pour MIME) réside dans la meilleure compression de données qu’il permet sans nécessiter d’algorithme compliqué de traitement : il offre un taux de compression comparable à UTF-8 pour les langues latines (anglais, français, allemand, roumain, suédois, tchèque, etc.). Il offre des taux de compression comparables à UTF-16 (et bien meilleur qu’UTF-8) pour les langues à écriture idéographique (notamment le chinois, le japonais) ainsi que pour le coréen (dans l‘écriture alphasyllabure hangul).
Comme UTF-8, UTF-16BE, UTF-16LE, UTF-32BE, UTF-32LE (mais à l’inverse de SCSU, ou même UTF-16 et UTF-32 qui sont dépendants de l’ordonnancement des octets dans les unités de codage sur 16 ou 32 bits et de la présence ou non d’un code « BOM », de l‘anglais Byte Order Mark, en tête de texte), il est totalement prédictif (il n’existe qu’une seule façon de coder en séquences d’octets une même séquence de points de code composant un texte).
Mais par rapport à UTF-8 et UTF-16, il améliore la compression du coréen transcrit seulement dans l’alphabet jamo de base.
Il offre un meilleur taux de compression (comparable à celui offert par SCSU) qu’UTF-8 et bien meilleur qu’UTF-16 pour les langues utilisant d’autres écritures qui utilisent la plupart du temps un nombre réduit de caractères, pris soit dans un même bloc de 128 points de code, soit parmi les codes de contrôles C0 et l’espace standard, en obtenant des taux également comparables aux codes des pages de codes et jeux de caractères 8 bits ou multioctets qui ont été développés dans le passé pour certaines langues ou familles de langues, tout en permettant d’être compatible avec la totalité du répertoire universel de l’UCS. C’est le cas de toutes les écritures alphabétiques simples, notamment l’écriture grecque (pour la transcription du grec moderne monotonique ou l’ancien grec classique, mais aussi pour le grec polytonique), cyrillique (pour la transcription du russe, bulgare, ukrainien, etc.), ou les abjads sémitiques (arabe, hébreu), et la plupart des abugidas brahmiques (comme la dévanagari pour la transcription de l’hindi ou du sanscrit, l’écriture tamoule, les écritures thaïe, khmère, lao, les écritures philippines, etc.)
Le codage BOCU-1 est contextuel et orienté vers le codage en suite d’octets indivisible. Il n’utilise qu’une seule variable d’état entière (contenant la valeur scalaire d’un point de code unique dépendant seulement d’un seul point de code précédemment encodé, donc limité à 21 bits).
Il ne doit être utilisé que pour coder sous la forme de séquences d’octets des suites de points de code standards dotés d’une valeur scalaire dans les normes ISO/CEI 10646 et Unicode (donc uniquement dans U+0000 à U+D7FF, ou U+E000 à U+10FFFF). Comme les autres schémas de transformations conformes à Unicode (tels que UTF-8), il autorise le codage des non-caractères (tels que U+FFFE..U+FFFF) et uniquement ceux-ci (contrairement au codage GB-18030 utilisé en République populaire de Chine, et qui permet de coder aussi la totalité des points de code standards de l‘UCS, mais qui contient aussi des extensions permettant, temporairement, de représenter des caractères non encore normalisés dans l’UCS au niveau international au moyen d’un nombre plus important de positions d’usage privé dans leur mappage possible vers l’UCS, mais réservées dans un registre permanent au sein de cette norme nationale).
La variable d’état prend une valeur initiale fixe, qui est restaurée après chaque occurrence d’un caractère de contrôle C0 dans le texte (U+0000 à U+001F) et qui correspond au milieu de la colonne des 128 caractères de l’US-ASCII : U+0040.
L’encodage BOCU d’un nouveau point de code dépend de celui-ci :
La variable d’état n’est pas modifiée après le codage d’une espace (U+0020), afin de ne pas briser le taux de compression dans les textes non latins les plus courants (ce n’était pas le cas dans la version initiale appelée simplement « BOCU » par ses concepteurs, et que la version BOCU-1 référencée par la note technique UTN#6 d’Unicode a améliorée sur ce point).
Dans tous les autres cas, la variable d’état prend la valeur d’un point de code au milieu du bloc dans lequel se situe le dernier caractère qui a été encodé. Des exceptions sont faites pour les écritures nécessitant des blocs plus larges ou non alignés sur des multiples de 128 points de code :
Les douze caractères de contrôle invariants pour MIME, et qui sont toujours codés avec le même octet quelle que soit leur position dans le texte sont :
(Ces douze caractères de contrôle s’ajoutent à l’espace normale U+0020 codée 0x20 et décrite ci-dessus, qui est aussi invariante mais ne déclenche pas de réinitialisation de la variable d’état et ne peut donc pas servir à la resynchronisation du flux).
Les 20 autres caractères de contrôle C0, bien que codés aussi eux-mêmes en utilisant un seul octet de valeur scalaire identique (afin de préserver l’ordre de tri binaire), sont aussi utilisés comme octets suffixe dans la représentation différentielle des autres caractères.
À ces valeurs d’octets fixes s’ajoute une valeur réservée qui ne représente elle-même aucun point de code et ne peut figurer non plus comme premier octet du séquence multi-octet représentant un point de code :
Le codage différentiel des autres points de code dotés d’une valeur scalaire (caractères ou non-caractères) doit permettre de coder distinctement des différences positives ou négatives entre tout point de code possible et celui contenu dans la variable d’état : les petites différences (valeurs de delta positives ou négatives) nécessitent moins d’octets que les grandes différences.
Parmi ces différences, celles dans l’intervalle delta de -64 à +63 ne nécessitent qu’un seul octet, alors que les différences plus grandes sont représentées par un octet préfixe discriminant, indiquant la longueur de la séquence totale, suivi de un ou plusieurs octets de suffixe.
Dans la table ci-dessus, les premiers octets d’une séquence (octets de préfixe discriminants) sont indiqués en gras comme dans le reste de cet article. Les octets de suffixe varient de 0x01 à 0xFF mais ne peuvent pas prendre toutes les valeurs possibles : les 13 valeurs d’octet réservées aux caractères de contrôle invariants et à l’espace sont exclues de ce codage (qui utilise un système numéral de base 243 avant de mapper les chiffres de ce système sur les valeurs d’octets autorisées).
Le détail de ce codage, sur la façon dont il a été déterminé et finalement utilisé, est expliqué dans les sous-sections qui suivent.
Sachant que tous les caractères de contrôle C0 (U+0000 à U+001F) et l’espace U+0020 sont codés aussi par un octet unique, et qu’un octet est réservé pour la fonction de synchronisation ou de marque de fin de texte, cela laisse 222 valeurs d’octets possibles dans un intervalle continu (de 0x21 à 0xFE) pour coder les petits deltas avec un octet unique, et pour coder les octets de préfixe discriminants des plus grands deltas.
La valeur d’octet médiane de cet intervalle est 0x90, qui sera utilisée pour coder un delta nul (c’est-à-dire pour encoder un point de code égal à celui dans la variable d’état).
Les petits deltas de -64 à +63 seront codés relativement à cette valeur d’octet, donc avec les valeurs d’octet entre 0x50 et 0xCF.
Dans BOCU-1, les valeurs d’octets suffixes ne sont pas séparées des valeurs d’octets préfixes, mais les deux types excluent les douze valeurs d’octets réservées aux caractères de contrôle invariants et à l’espace (U+0020).
Sachant que les douze caractères de contrôle C0 invariants (U+0000, U+0007 à U+000F, U+001A et U+001B) et l’espace U+0020 ne sont jamais utilisés non plus comme octets de suffixe (pour préserver la compatibilité MIME), cela laisse 243 valeurs possibles (de 0x01 à 0x06, de 0x10 à 0x19, et de 0x1C à 0x1F et de 0x21 à 0xFF) pour le (ou les) octet(s) de suffixe utilisés (après un premier octet de préfixe discriminant) pour coder les valeurs plus grandes (négatives ou positives) de deltas sur plusieurs octets.
Les valeurs de deltas sont codées de sorte que les octets uniques et les octets de préfixe sont ordonnées de la valeur des deltas négatifs la plus grande en valeur absolue à la valeur des deltas positifs les plus grands.
Pour coder ces grands deltas sur plusieurs octets, on utilisera un octet de préfixe discriminant parmi :
et un ou plusieurs octets de suffixe parmi :
Indépendamment du signe des deltas, on a 47 valeurs d’octets de préfixe disponibles et 243 valeurs d’octets de suffixe, pour coder jusqu’à 1 113 823 valeurs négatives et 1 113 984 valeurs positives de delta.
Pour obtenir la compression maximale, on a intérêt à maximiser les codes les plus courts en utilisant le plus possible de séquences sur 2 octets pour les valeurs de deltas les plus faibles et les plus probables :
Les séquences codées sur 3 octets utilisent :
Les séquences codées sur 4 octets utilisent :
La totalité des points de code ayant une valeur scalaire dans l’UCS peut donc être encodé sous cette forme compressée tout en conservant leur ordre binaire relatif.
Les deltas sont ajustés en valeur absolue en retranchant la valeur absolue minimale de chaque intervalle auxquels ils appartiennent, puis ils sont exprimés dans la base numérique 243 (par divisions euclidiennes successives de la valeur absolue du delta ajusté dans chaque intervalle de codage) afin obtenir une suite de chiffres entre 0 et 242 dans cette base. Le signe est alors rétabli sur ce décalage (par une opération de complément à 243 pour les deltas négatifs), et chaque chiffre de cette base qui est alors mappé sur les 243 valeurs possibles d'octets de suffixe décrits ci-dessus.
L'ordre croissant de mappage des 243 décalages signés calculés suit la progression binaire croissante des 243 valeurs d’octets de suffixe utilisés (de 0x01 à 0x06, de 0x10 à 0x19, et de 0x1C à 0x1F et de 0x21 à 0xFF), lesquels sont codés dans l’ordre du chiffre de poids fort (dans la base 243) vers le chiffre unitaire de poids faible, ce qui assure que la compression finale produira aussi un code ordonné dans l’ordre binaire.
Il est aussi destiné à être utilisé pour la compression de textes courts (par exemple pour le stockage de champs dans une base de données), pour lesquels il est aussi souhaitable de pouvoir effectuer de la recherche en texte plein. À l’inverse des codages UTF-8/16/32, il n’offre pas une possibilité de resynchronisation depuis une position aléatoire dans un texte. Mais des possibilités limitées de resynchronisation existent dans les textes contenant des phrases et paragraphes (et non des mots isolés), par le fait que les espaces, tabulations et séparateurs de ligne sont laissés inchangés (ces possibilités peuvent ne pas exister dans les textes idéographiques écrits sans espace).
Ce schéma de compression est seulement adapté au stockage ou à la transmission de textes conformes à Unicode ou l’ISO/CEI 10646, il n’est pas conçu pour fonctionner correctement avec les données binaires pour lesquels les formats de compression de fichiers quelconques (comme deflate ou compress utilisés dans MIME, ou les formats d’archive zip, gzip, bzip2) sont mieux adaptés. Ces formats de compression peuvent être utilisés en complément pour améliorer encore les textes codés avec BOCU-1.
Son implémentation est très simple à mettre en œuvre et à certifier, contrairement aux algorithmes génériques de compression de données binaires qui nécessitent souvent la gestion d’un nombre élevé de variables d’état et de tampons de taille souvent variable, ou qui travaille sur des entités aussi petites que le bit : les performances seront donc souvent bien meilleures pour un traitement local au sein d’un même processus ou entre processus d’un même système hôte, qu’avec les algorithmes de compression génériques (qui en revanche pourront s’avérer parfois meilleurs dans le cas de données très volumineuses ou accédées depuis un médium lent ou via un réseau, au prix d’une charge processeur bien supérieure).
Ce schéma de codage, qui ne fait pas partie du standard Unicode mais y est mentionné dans une note technique optionnelle, est le seul qui soit restreint dans son utilisation par le fait qu’il est couvert par un brevet décrivant un algorithme plus général (brevet détenu actuellement par IBM car il a été créé et publié par des personnes qui étaient alors employées par lui).
Cependant IBM a accepté d’en offrir des licences gratuites (sans paiement de redevance ou royalties) à tous les développeurs qui en feraient la demande en produisant une version pleinement conforme à la documentation fournie par IBM (ce qu’IBM peut vérifier, mais ce qui en interdit toute modification, amélioration ou adaptation à des algorithmes dérivés, sans obtention d’une licence). Le brevet couvre notamment la méthode et les principes de codage utilisés.
BOCU-1 est une version particulière (libérée des contraintes de royalties) de l’algorithme de codage plus général BOCU (qui est, lui, soumis à l’obtention d’un accord de licence) et qui permet de réserver d’autres valeurs d’octets invariants ou interdits pour le codage des caractères de l’UCS mais nécessaires à d’autres fonctions ou données dans certains protocoles (par exemple pour le codage complet de l’UCS dans un code barre restreint à 47 valeurs d’octets utilisables, ou encore dans le système de noms de domaines DNS restreint à 37 valeurs d’octets utilisables).
IBM a mis en œuvre (dans sa bibliothèque ICU, fournie sous la licence libre X modifiée pour ICU et signée par IBM) une variante de cet algorithme plus général BOCU pour la compression des clés de collation générées pour l’algorithme de tri normalisé UCA Unicode, afin de compresser les poids de collation de chaque niveau, en évitant d’utiliser certaines valeurs d’octets réservés (par exemple l’octet nul) ce qui permet de stocker les clés de collation dans des chaînes de caractères C où le caractère nul est réservé, et un code est réservé au séparateur de clés de tri multiniveaux.
La variante libre BOCU-1 de l’algorithme BOCU souffre de plusieurs problèmes :
La partition des points de code en grands-sous-ensembles présuppose que les points de code présents dans un texte seront majoritairement dans des blocs de cette taille. L’algorithme n’a pas été revu pour prendre en compte les écritures dont les points de code utilisés sont distribuées sur plusieurs blocs distincts.