Difference between revisions of "FPC Unicode support/fr"

From Lazarus wiki
Jump to navigationJump to search
Line 24: Line 24:
  
 
=== DefaultSystemCodePage ===
 
=== DefaultSystemCodePage ===
* '''Purpose''': determines how CP_ACP is interpreted
+
* '''Usage''': détermine comment CP_ACP est interprété
* '''Initial value''':
+
* '''Valeur initiale''':
** Windows: The result of the ''GetACP'' OS call, which returns the Windows ANSI code page.
+
** Windows: C'est le résultat de l'appel système à ''GetACP'', qui retourne la page de code ANSI de Windows.
 
** iOS: UTF-8
 
** iOS: UTF-8
** Unix (excluding iOS): Based on the currently set ''LANG'' or ''LC_CTYPE'' environment variables. This is usually UTF-8, but that is not guaranteed to be the case.
+
** 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.
** Other platforms: CP_ACP (these platforms currently do not support multiple code pages, and are hardcoded to use their OS-specific code page in all cases)
+
** 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''': you can modify this value by calling ''SetMultiByteConversionCodePage(CodePage: TSystemCodePage)''
+
* '''Modifications''': vous pouvez modifier cette valeur en appelant ''SetMultiByteConversionCodePage(CodePage: TSystemCodePage)''
* '''Notes''': Since the value of this variable can be changed, it is not a good idea to use its value to determine the real OS "default system code page" (unless you do it at program startup and are certain no other unit has changed it in its initialisation code).
+
* '''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 ===
 
=== DefaultFileSystemCodePage ===

Revision as of 08:35, 30 July 2014

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 chaîne de données. 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

  • Purpose: defines the code page to which file/path names are translated before they are passed to OS API calls, if the RTL uses a single byte OS API for this purpose on the current platform. This code page is also used for intermediate operations on file paths inside the RTL before making OS API calls.
  • Initial value:
    • Windows: UTF-8, because the RTL uses UTF-16 OS API calls (so no data is lost in intermediate operations).
    • OS X and iOS: UTF-8 (as defined by Apple)
    • Unix (excluding OS X and iOS): DefaultSystemCodePage, because the encoding of file names is undefined on Unix platforms (it's an untyped array of bytes that can be interpreted in any way; it is not guaranteed to be valid UTF-8)
    • Other platforms: same as DefaultSystemCodePage
  • Modifications: you can modify this value by calling SetMultiByteFileSystemCodePage(CodePage: TSystemCodePage)
  • Notes: the Unix/OS X/iOS settings only apply in case the cwstring widestring manager is installed, otherwise DefaultFileSystemCodePage will have the same value as DefaultSystemCodePage after program startup.

DefaultRTLFileSystemCodePage

  • Purpose: defines the code page to which file/path names are translated before they are returned from RawByteString file/path RTL routines. Examples include the file/path names returned by the RawbyteString versions of SysUtils.FindFirst and System.GetDir. The main reason for its existence is to enable the RTL to provide backward compatibility with earlier versions of FPC, as these always returned strings encoded in whatever the OS' single byte API used (which was usually what is now known as DefaultSystemCodePage).
  • Initial value
    • Windows: DefaultSystemCodePage, for backward compatibility.
    • OS X and iOS: UTF-8, for backward compatibility (it was already always UTF-8 in the past, since that's what the OS file APIs return and we did not convert this data).
    • Unix (excluding OS X and iOS): DefaultSystemCodePage, for the same reason as with DefaultFileSystemCodePage. Setting this to a different value than DefaultFileSystemCodePage is a bad idea on these platforms, since any code page conversion can corrupt these strings as their initial encoding is unknown.
    • Other platforms: same as DefaultSystemCodePage
  • Modifications: you can modify this value by calling SetMultiByteRTLFileSystemCodePage(CodePage: TSystemCodePage)
  • Notes: same as for 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

These types are the same as the old PChar/Char types. In all compiler modes except for {$mode delphiunicode}, PChar/Char are also still aliases for PAnsiChar/AnsiChar. Their code page is implicitly CP_ACP and hence will always be equal to the current value of DefaultSystemCodePage.

PWideChar/PUnicodeChar and WideChar/UnicodeChar

These types remain unchanged. WideChar/UnicodeChar can contain a single UTF-16 code unit, while PWideChar/PUnicodeChar point to a single or an array of UTF-16 code units.

In {$mode delphiunicode}, PChar becomes an alias for PWideChar/PUnicodeChar and Char becomes an alias for WideChar/UnicodeChar.

UnicodeString/WideString

These types behave the same as in previous versions:

  • Widestring is the same as a "COM BSTR" on Windows, and an alias for UnicodeString on all other platforms. Its string data is encoded using UTF-16.
  • UnicodeString is a reference-counted string with a maximum length of high(SizeInt) UTF-16 code units.

Ansistring

AnsiStrings are reference-counted types with a maximum length of high(SizeInt) bytes. Additionally, they now also have code page information associated with them.

The most important thing to understand about the new AnsiString type is that it both has a declared/static/preferred/default code page (called static code page from now on), and a dynamic code page. The static code page tells the compiler that when assigning something to that AnsiString, it should first convert the data to that static code page (except if it is CP_NONE, see #RawByteString below). The dynamic code page is a property of the AnsiString which, similar to the length and the reference count, defines the actual code page of the data currently held by that AnsiString.

Static code page

The static code page of an AnsiString can only be defined by declaring a new type as follows:

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

The static code page of a variable declared as plain AnsiString is CP_ACP. In effect, the AnsiString type is now semantically defined in the System unit as

type
  AnsiString = type AnsiString(CP_ACP);

Another predefined AnsiString(X) type in the System unit is UTF8String:

type
  UTF8String = type AnsiString(CP_UTF8);

Once you have defined such a custom AnsiString(X) type, you can use it to declare variables, parameters, fields etc as usual.

Dynamic code page

If a string with a static code page X1 is assigned to a string with static code page X2 and X1<>X2, the string data will generally first be converted to said code page X2 before assignment, and as a result the dynamic code page of the destination string will be X2. When assigning a string to a plain AnsiString (= AnsiString(CP_ACP)) or ShortString, the string data will however be converted to DefaultSystemCodePage. The dynamic code page of that AnsiString(CP_ACP) will then be the current value of DefaultSystemCodePage (e.g. 1250 for the Windows-1250 code page), even though its static code page is CP_ACP (which is a constant <> 1250). This is one example of how the static code page can differ from the dynamic code page. Subsequent sections will describe more such scenarios.

Note: as mentioned above, whether or not a potential code page conversion happens only depends on the static code pages of the involved strings. This means that if you assign one AnsiString(X) to another AnsiString(X) and the former's dynamic code was different from X, the string data will not be converted to code page X by the assignment.

RawByteString

The RawByteString type is defined as

type
  RawByteString = type AnsiString(CP_NONE);

As mentioned earlier, the results of conversions from/to the CP_NONE code page are undefined. As it does not make sense to define a type in the RTL whose behaviour is undefined, the behaviour of RawByteString is somewhat different than that of other AnsiString(X) types.

As a first approximation, RawByteString can be thought of as an "untyped AnsiString": assigning an AnsiString(X) to a RawByteString has exactly the same behaviour as assigning that AnsiString(X) to another AnsiString(X) variable with the same value of X: no code page conversion or copying occurs, just the reference count is increased.

Less intuitive is probably that when a RawByteString is assigned to an AnsiString(X), the same happens: no code page conversion or copying, just the reference count is increased. Note that this means that results from functions returning a RawByteString will never be converted to the destination's static code page. This is another way in which the dynamic code page of an AnsiString(X) can become different from its static code page.

This type is mainly used to declare const, constref and value parameters that accept any AnsiString(X) value without converting it to a predefined static code page. Note that if you do this, the routine accepting those parameters should be able to handle strings with any possible dynamic code page.

var and out parameters can also be declared as RawByteString, but in this case the compiler will give an error if an AnsiString(X) whose static code page is different from CP_NONE is passed in. This is consistent with var and out parameters in general: they require an exactly matching type to be passed in. You can add an explicit RawByteString() typecast around an argument to remove this error, but then you must be prepared to deal with the fact that the returned string can have any dynamic code page.

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