FPC Unicode support/fr

From Lazarus wiki
Jump to navigationJump to search

English (en) español (es) français (fr) русский (ru)

Introduction

Jusqu'à la version 2.6.x inclus, la RTL est basée sur ceux de Turbo Pascal et Delphi 7. Cela signifie qu'elle était au départ basé sur les types shortstring, ansistring et pchar. Aucun de ces types n'avait d'information d'encodage associé avec eux, mais ils étaient supposés être implicitement encodés dans l'"encodage système par défaut" et étaient passés aux API système sans aucune conversion.

Dans Delphi 2009, Embarcadero a basculé l'ensemble de la RTL vers le type UnicodeString, qui représente des chaînes utilisant UTF-16. En plus, ils sont rendu le type AnsiString "sensible (aware) à la page de code". Cela signifie que les AnsiStrings dès lors contiennent la page de code selon lequel les données doivent être interprétées.

Le support au niveau du langage de FPC est déjà disponible dans les versions en cours de développement du compilateur (FPC 2.7.1/trunk). Le support au niveau RTL n'est pas encore complet. Cette page donne une vue d'ensemble des comportements relatifs à la page de code pour ces types de chaînes, le niveau actuel du support par la RTL et des possibles voies d'amélioration futures pour ce support.

Code pages

Une page de code définit comment les octets individuels d'une chaînes sont interprétés i.e. quelle lettre, quel symbole ou autre caractère graphique correspond à chaque octet ou séquence d'octets.

Identificateurs de page de code

Un identificateur de page de code est toujours enregistré comme un TSystemCodePage, qui est un alias pour Word. La valeur représente la page de code correspondante telle que définie par Microsoft Windows. En plus, il y a 3 valeurs spéciales de code de page :

  • CP_ACP: cette valeur représente la "page de code par défaut" en cours. Voir #Réglage de la page de code pour plus d'information.
  • CP_OEM: cette valeur représente la page de code OEM. Sur les plates-formes Windows, ceci correspond à la page de code utilisée par la console (par exemple les fenêtres cmd.exe). Sur d'autres plates-formes, cette valeur est interprétée de la même façon que CP_ACP.
  • CP_NONE: cette valeur indique qu'aucune information de page de code n'a été associée avec la donnée chaîne. Le résultat de toute opération explicite ou implicite qui convertit cette donnée en une autre page de code est indéfinie

Note: les identificateurs de page de code sont différent des noms de page de code tels qu'ils sont utilisés dans la directive {$codepage xxx} (qui est déjà disponible dans la version stable de FPC). Les noms de page de code sont des noms d'unités individuelles de page de code exposés dans l'unité de jeu de caractères, qui ont des noms tels que cp866 et cp1251 et utf8.

Réglage de la page de code

L'unité system contient plusieurs variables globales qui indiquent la page de code par défaut utilisée par certaines opérations.

DefaultSystemCodePage

  • Usage: détermine comment CP_ACP est interprété
  • Valeur initiale:
    • Windows: C'est le résultat de l'appel système à GetACP, qui retourne la page de code ANSI de Windows.
    • iOS: UTF-8
    • Unix (sauf iOS): Basé sur le réglage actuel des variables d'environnement LANG ou LC_CTYPE. C'est en général UTF-8, mais il n'est pas garanti que cela soit le cas.
    • Autres plates-formes: CP_ACP (ces plates-formes ne supportent actuellement pas les pages de code multiples, et sont codés en dur pour utiliser la page de code spécifique au système dans tous les cas)
  • Modifications: vous pouvez modifier cette valeur en appelant SetMultiByteConversionCodePage(CodePage: TSystemCodePage)
  • Notes: Depuis que cette variable peut être modifiée, ce n'est plus une bonne idée d'utiliser cette valeur pour déterminer la "page de code par défaut" réelle du système (à moins de le faire au démarrage du programme et d'être certain qu'aucune autre unité ne l'a changé dans son code d'initialisation).

DefaultFileSystemCodePage

  • Usage: Définit la page de code vers laquelle les noms de chemin/fichier sont traduits avant d'être passé lors d'un appel à une API système, si la RTL utilise une API système à simple octet pour cette usage sur la plate-forme courante. Ce page de code est aussi utilisée pour les opérations intermédiaires sur les chemins d'accès dans la RTL avant de faire des appels aux API système.
  • Valeur initiale:
    • Windows: UTF-8, parce que la RTL utilise des appels aux API système UTF-16 (donc aucune donnée n'est perdue dans les opérations intermédiaires).
    • OS X and iOS: UTF-8 (comme défini par Apple)
    • Unix (mis à part OS X et iOS): DefaultSystemCodePage, parce que l'encodage des fichiers est indéfini sur les plates-formes Unix (c'est un tableau non typé d'octets qui peut être interprété comme on veut ; il n'est pas garanti d'être de l'UTF-8 valide)
    • Autres plates-formes: identique à DefaultSystemCodePage
  • Modifications: vous pouvez modifier cette valeur en appelant SetMultiByteFileSystemCodePage(CodePage: TSystemCodePage)
  • Notes: Les réglages Unix/OS X/iOS s'appliquent seulement dans le cas où le gestionnaire de widestring cwstring est installé, sinon DefaultFileSystemCodePage aura la même valeur que DefaultSystemCodePage après le démarrage du programme.

DefaultRTLFileSystemCodePage

  • Usage: définit la page de code vers laquelle les noms de fichier/chemin sont traduits avant d'être retournées par les routines RTL pour les fichier/chemin RawByteString. Des exemples sont dans les noms de fichier/chemin retournés par les versions RawbyteString de SysUtils.FindFirst et System.GetDir. La principale raison de son existence est de rendre la RTL capable de fournir la compatibilité ascendante avec les versions antérieures de FPC, comme celles-ci retournaient toujours des chaînes encodées pour les API système en simple octet utilisées (qui étaient habituellement ce qui est connu maintenant comme DefaultSystemCodePage).
  • Valeur initiale
    • Windows: DefaultSystemCodePage, pour compatibilité ascendante.
    • OS X and iOS: UTF-8, pour compatibilité ascendante (c'était déjà toujours UTF-8 dans le passé, puisque c'est ce que les API de fichiers de l'OS retourne et nous ne convertissions pas cette donnée).
    • Unix (mis à part OS X et iOS): DefaultSystemCodePage, pour la même raison qu'avec DefaultFileSystemCodePage. Régler celle-ci à une autre valeur que DefaultFileSystemCodePage est une mauvaise idées sur ces plates-formes, puisque toute conversion peut corrompre ces chaînes car leur encodage initial est inconnu.
    • Autres plates-formes: comme pour DefaultSystemCodePage
  • Modifications: Vous pouvez modifier cette valeur en appelant SetMultiByteRTLFileSystemCodePage(CodePage: TSystemCodePage)
  • Notes: les mêmes que pour DefaultFileSystemCodePage.

Strings

String/character types

Shortstring

La page de code d'une shortstring est implicitement CP_ACP d'où elle sera toujours égale à la valeur courante de DefaultSystemCodePage.

PAnsiChar/AnsiChar

Ces types sont les mêmes que les anciens types PChar/Char. Dans tous les modes du compilateur sauf pour {$mode delphiunicode}, PChar/Char sont aussi encore des alias pour PAnsiChar/AnsiChar. Leur page de code est implicitement CP_ACP et donc toujours égale à la valeur courante de DefaultSystemCodePage.

PWideChar/PUnicodeChar et WideChar/UnicodeChar

Ces types demeurent inchangés. WideChar/UnicodeChar peuvent contenir une simple unité de code UTF-16, alors que PWideChar/PUnicodeChar pointe sur une simple unité de code ou un tableau d'unités de code en UTF-16.

En {$mode delphiunicode}, PChar devient un alias de PWideChar/PUnicodeChar et Char devient un alias de WideChar/UnicodeChar.

UnicodeString/WideString

Ces types se comporte comme dans les versions précédentes:

  • Widestring est le même qu'un "COM BSTR" dans Windows et un alias de UnicodeString sur toutes les autres plates-formes. Sa chaîne de données est encodée avec de l'UTF-16.
  • UnicodeString est une chaîne à comptage de référence avec une longueur maximale de high(SizeInt) en unités de code UTF-16.

Ansistring

Les AnsiStrings sont des chaînes à comptage de références avec une longueur maximal de high(SizeInt) octets. En plus, une information de code de page peut maintenant leur être associée.

La chose la plus importante à comprendre sur le nouveau type AnsiString est qu'il a à la fois une page de code déclarée/statique/préférée/par défaut (appelée page de code statique à partir de maintenant), et une page de code dynamique. La page de code statique dit au compilateur que lorsqu'on affecte quelque chose à cet AnsiString, il devrait d'abord convertir cette donnée vers cette page de code (sauf si c'est CP_NONE, voir #RawByteString plus bas). La page de code dynamique est une propriété de l'AnsiString qui, tels la longueur et le compteur de référence, définit la page de code en cours des données actuellement tenues par cette AnsiString.

Page de code statique

La page de code statique d'une AnsiString peut seulement être définie en déclarant un nouveau type comme suit:

type
  CP866String = type AnsiString(866); // note the extra "type"

La page de code statique d'une variable déclarée comme pure AnsiString est CP_ACP. En effet, le type AnsiString est maintenant sémantiquement défini dans l'unité System comme:

type
  AnsiString = type AnsiString(CP_ACP);

Un autre type AnsiString(X) prédéfini dans l'unité System est UTF8String:

type
  UTF8String = type AnsiString(CP_UTF8);

Une fois que vous avez défini tel type AnsiString(X), vous pouvez l'utiliser pour déclarer des variables, des paramètres, champs etc comme d'habitude.

Page de code dynamique

Si une chaîne avec une page de code statique X1 est affectée dans une chaîne avec une page de code X2 et que X1<>X2, la donnée chaîne sera généralement d'abord convertie vers la dite page de code X2 avant l'affectation et avec pour résultat, la page de code dynamique de la chaîne de destination sera X2. A l'affectation d'une chaîne vers une pure AnsiString (= AnsiString(CP_ACP)) ou ShortString, la donnée chaîne sera toutefois convertie vers DefaultSystemCodePage. La page de code dynamique de cette AnsiString(CP_ACP) sera alors la valeur actuelle de DefaultSystemCodePage (p.ex. 1250 pour la page de code Windows 1250), alors même que sa page de code statique est CP_ACP (qui est une constante <> 1250). C'est un exemple de comment la page de code statique peut différer de la page de code dynamique. Les sections suivantes décrivent plus de tels scénarios.

Note: comme mentionné au-dessus, qu'une conversion potentielle de page de code survienne ou pas dépend seulement de la page de code statique des chaînes impliquées. Cela signifie que si vous affectez une AnsiString(X) à une autre AnsiString(X) et que l'ancienne page de code dynamique était différente de X, la chaîne ne sera pas convertie vers la page de code X par l'affectation.

RawByteString

Le type RawByteString est défini comme

type
  RawByteString = type AnsiString(CP_NONE);

Comme mentionné avant, les résultats de conversions de/vers la page de code CP_NONE sont indéfinis. Comme cela n'a pas de sens de définir un type dans la RTL dont le comportement est indéfini, le comportement de RawByteString est quelque peu différent des autres types AnsiString(X).

Comme première approximation, RawByteString paut être considéré comme un "AnsiString non typé": affecter une AnsiString(X) vers une RawByteString a exactement le même comportement que d'affecter cet AnsiString(X) vers une autre variable AnsiString(X) avec la même valeur de X: aucune conversion de page de code ou copie ne se passe, seul le compteur de référence est incrémenté.

Moins intuitif est probablement le fait que lorsqu'une RawByteString est affectée vers une AnsiString(X), la meêm chose se produit: pas de conversion de page de code ni de copie, seulment une incrémentation du compteur. Notez que cela signifie que les résultats de fonctions retourant une RawByteString ne seront jamais converties vers la page de code de destination. C'est une autre manière par laquelle la page de code dynamique d'une AnsiString(X) peut devenir différente de sa page de code statique.

Ce type est principalement utilisé pour déclarer des const, constref et des paramètres par valeur qui acceptent toute valeur AnsiString(X) sans la convertir vers une page de code prédéfinie. Notez que si vous faites cela, la routine acceptant ces paramètres devrait être capable de manipuler des chaînes avec n'importe quelle page de code dynamique.

Les paramètres var et out peuvent être aussi déclarés comme RawByteString, mais dans ce cas, le compilateur donnera une erreur si une AnsiString(X) dont le page de code statique est différente de CP_NONE est passé dedans. C'est consistant avec les paramètres var et out en général: ils nécessitent une exacte correspondance de type à passer dedans. Vous pouvez ajouter une conversion explicite de type vers RawByteString() pour supprimer l'erreur, mais vous devez être préparé à traiter le fait que la chaîne retournée peut avoir aucune page de code dynamique.

String concatenations

Normally, in Pascal the result type of an expression is independent of how its result is used afterwards. E.g. multiplying two longints on a 32 bit platform and assigning the result to an int64 will still perform the multiplication using 32 bit arithmetic, and only afterwards the result is converted to 64 bit.

Code page-aware strings are the only exception to this rule: concatenating two or more strings always occurs without data loss, although afterwards the resulting string will of course still be converted to the static code page of the destination (which may result in data loss).

Assigning the result of a concatenation to a RawByteString is again special:

  • if all concatenated strings have the same dynamic code page, the result will have this code page too
  • in other cases the result will be converted to CP_ACP (we may add an option in the future to change this RawByteString behaviour, as it is not very practical).

String constants

String constants are parsed by FPC as follows:

  • if a file contains a {$codepage xxx} directive (e.g. {$codepage UTF8}), then string constants are interpreted according to that code page, otherwise
  • if the file starts with an UTF-8 BOM, then string constants are interpreted as UTF-8 strings, otherwise
  • string constants are copied without any translation into an internal buffer and are interpreted as characters using one of the following code pages:
    • the DefaultSystemCodePage of the computer on which the compiler itself is currently running when {$modeswitch systemcodepage} is active (i.e., compiling the source code on a different system may cause string constants to be interpreted differently; this switch is available for Delphi compatibility and is enabled by default in {$mode delphiunicode})
    • CP_ACP in case {$modeswitch systemcodepage} is not active (for backward compatibility with previous FPC versions)

In all but the last case, the actual code page of the source file is known. This knowledge is required when the compiler is forced to convert string constants to a different code page. Therefore, in the last case a default is used in such situations: strings are assumed to be encoded in code page 28591 (ISO 8859-1 Latin 1; Western European). This assumed or actual code page is referred to as the source file code page below.

When a string constant is assigned to an AnsiString(X) either in code or as part of a typed constant or variable initialisation, then

  • if X = CP_NONE (i.e., the target is a RawByteString), the result is the same as if the constant string were assigned to an AnsiString(CP_ACP)
  • if X = CP_ACP and the code page of string constant is different from CP_ACP, then the string constant is converted, at compile time, to the source file code page. If the string constant's code page is also CP_ACP, it will be stored in the program unaltered with a code page of CP_ACP and hence its meaning/interpretation will depend on the actual value of DefaultSystemCodePage at run time. This ensures compatibility with older versions of FPC when assigning string constants to AnsiString variables without using a {$codepage xxx} directive or UTF-8 BOM.
  • for other values of X, the string constant is converted, at compile time, to code page X

Similarly, if a string constant is assigned to a UnicodeString, the string constant is converted, at compile time, from the source file code page to UTF-16.

For ShortString and PChar, the same rule as for AnsiString(CP_ACP) is followed.

Note that symbolic string constants will be converted at compile time to the appropriate string type and code page whenever they are used. This means that there is no speed overhead when using a single string constant in multiple code page and string type contexts, only some data size overhead.

From the above it follows that to ensure predictable interpretation of string constants in your source code, it is best to either include an explicit {$codepage xxx} directive (or use the equivalent -Fc command line option), or to save the source code in UTF-8 with a BOM.

Indexation de chaîne

Rien ne change dans l'indexation de chaînes. Chaque élément d'une chaîne UnicodeString/WideString est à 2 octets et chaque élément de tout autre type de chaîne est à 1 octet. Le mécanisme d'indexation de chaîne ignore totalement les pages de code et les points de code composites.

Sections anciennes ou obsolètes

Warning-icon.png

Avertissement: Ces sections sont conservées à titre historique - SVP, mettez à jour les sections du dessus avec cette information si elle est toujours applicable. Depuis FPC 2.7, (version en cours de développement), le support intensif d'Unicode a été implémenté.

Support de l'Unicode de Tiburon

Voici quelques informations au sujet du support de l'implémentation de l'Unicode de Tiburon's Unicode.

http://blogs.codegear.com/abauer/2008/01/09/38845

http://blogs.codegear.com/abauer/2008/07/16/38864

Etat du support d'Unicode dans FPC jusqu'ici

Actuellement, FPC 2.3.x a un nouveau type nommé UnicodeString. C'est similaire à un type WideString. La différence étant que UnicodeString bénéficie du comptage de référence sur toutes les plates-formes.

Tout le travail d'implémentation est actuellement fait dans une branche svn séparée: http://svn.freepascal.org/svn/fpc/branches/cpstrnew

User visible changes

(non traduit) Full support of code page aware strings is not possible without breaking some existing code. The following list tries to summarize the most important user visible changes.

  • The string header has two new fields: encoding and element size. On 32 Bit platforms this increases the header size by 4 and on 64 bit platforms by 8 bytes.
  • WideCharLenToString, UnicodeCharLenToString, WideCharToString, UnicodeCharToString and OleStrToString return an UnicodeString instead of an Ansistring before.
  • the type of the dest parameter of WideCharLenToString and UnicodeCharLenToString has been changed from Ansistring to Unicodestring
  • UTF8ToAnsi and AnsiToUTF8 take a RawByteString now

Feuille de route du support par la RTL d'Unicode avec UnicodeString

Sujet Etat Commentaire Affecté à
Variables Locale Not implemented Les variables font toutes 1 octet en taille et ne peuvent tenir de valeur de la taille de UnicodeChar. Par exemple: Le séparateur des milliers russe est un espace non sécable $00A0 qui ne peut tenir dans la variable ThousandSeparator (type Char standard).
TStrings Not implemented Il n'y a pas de version UnicodeString de TStrings
TStringList Not implemented Il n'y a pas de version UnicodeString de TStringList
Pos() Working

Feuille de route du support par la RTL d'Unicode avec UTF8String

Sujet Etat Commentaires Affecté à
UTF8String Not implemented Nécessite une réelle implémentation. Est pour l'instant uniquement un alias pour ansistring.
TStrings Not implemented Il n'y a pas de version UTF8String pour TStrings
TStringList Not implemented Il n'y a pas de version UTF8String pour TStringList

Voir aussi