Symbian
Symbian OS Library

SYMBIAN OS V9.3

[Index] [Spacer] [Previous] [Next]



How to create a character conversion plug-in DLL


Summary

The following steps are involved in the process of creating a plug-in DLL. Each step is described in more detail in following sections.

  1. Create the source file. This is a text file that contains pairs of hexadecimal numbers. The first number in each pair is the encoding of a character in the foreign character set, and the second is the Unicode encoding of the same character.

  2. Create the control file. This is a text file that specifies the conversion algorithms to convert both ways between ranges of characters, and other information.

  3. Invoke cnvtool on the source and control files. This generates a cpp file referred to as the cnvtool-generated cpp file.

  4. Create a cpp file which implements the plug-in DLL interface (defined in convplug.h) using the global objects created in the cnvtool-generated cpp file, if necessary.

  5. Create an mmp file which is used to build the plug-in DLL. Specify \epoc32\release\build variant\convplug.def as the filename in the deffile statement.

  6. Build the plug-in DLL and install it into the \system\charconv\ directory.

  7. The DLL is then available to be loaded by CCnvCharacterSetConverter::PrepareToConvertToOrFromL().

The process is summarised by the following diagram:

[Top]


The source file

The source file is a text file which contains a table of mappings between Unicode and the foreign character set. The table consists of two tab-separated columns. The first column lists the foreign character code. The second lists the corresponding Unicode character code. Both codes are in hexadecimal. The table can contain further hex columns if the -columns command line flag is used, (see the Running cnvtool section, below). Another column is optional it contains the Unicode name following a comment sign "#", provided to make the file more readable.

In some cases, the foreign character codes that appear in the source file need to be processed in some way before being used in the binary output file. Specifying how they should be processed is done by including a line in the following format in the source file:

SET_FOREIGN_CHARACTER_CODE_PROCESSING_CODE [Perl code]

This affects all lines in the source file beneath it until the next such line. If SET_FOREIGN_CHARACTER_CODE_PROCESSING_CODE is followed by whitespace only, the foreign character codes in the subsequent lines are not processed.

The Perl code must return a number using the variable $foreignCharacterCode as its input parameter. For example, if the high bit of each foreign character is off in the source file but is required to be on in the output file, the Perl code (assuming the foreign character set uses only one byte for each character) would be:

return $foreignCharacterCode|0x80;

[Top]


The control file


Introduction

The control file is a text file which specifies the conversion algorithms to convert (both ways) between ranges of characters, and other information. It also specifies the code(s) of the character(s) to use to replace unconvertible Unicode characters, the endian-ness of the foreign character set (if single characters may be encoded by more than one byte) and the preferred character to use when a character has multiple equivalents in the target character set.

The control file (like the source file) is case insensitive and permits comments beginning with a "#" and extending to the end of the line. It also permits blank lines and leading and trailing whitespace on non-blank lines.

There are four sections in the control file: the header, the foreign variable-byte data, the foreign-to-Unicode data and the Unicode-to-foreign data.


The header

The header consists of two lines in fixed order. Their format is as follows (alternatives are separated by a |, single space characters represent single or multiple whitespace characters):

Endianness Unspecified|FixedLittleEndian|FixedBigEndian

ReplacementForUnconvertibleUnicodeCharacters <see-below>

The value of Endianness is only an issue for foreign character sets where single characters may be encoded by more than one byte. The value of ReplacementForUnconvertibleUnicodeCharacters is a series of one or more hexadecimal numbers (not greater than 0xff) separated by whitespace, each prefixed with 0x. These byte values are output for each Unicode character that has no equivalent in the foreign character set (when converting from Unicode to foreign).


The foreign variable-byte data

This section is contained within the following lines:

StartForeignVariableByteData

EndForeignVariableByteData

In between these lines are one or more lines, each consisting of two hexadecimal numbers (each prefixed with 0x and not greater than 0xff), followed by a decimal number. All three numbers are separated by whitespace. Each of these lines indicates how many bytes make up a foreign character code for a given range of values for the initial foreign byte. The two hexadecimal numbers are the start and end of the range of values for the initial foreign byte (inclusive), and the decimal number is the number of subsequent bytes. The way these bytes are put together to make the foreign character code is determined by the value of Endianness in the header of the control file. For example, if the foreign character set uses only a single byte per character and its first character has code 0x07 and its last character has code 0xe6, the foreign variable-byte data would be:

StartForeignVariableByteData
0x07 0xe6 0
EndForeignVariableByteData


The foreign-to-Unicode data

This section is contained within the following lines:

StartForeignToUnicodeData

EndForeignToUnicodeData

In between these two lines are one or more of lines in format A (defined below). These may be optionally followed by one or more of lines in format B (defined below), in which case the lines in format A and format B are separated by the line:

ConflictResolution

Each line in format A indicates the conversion algorithm to be used for a particular range of foreign character codes. Lines in format A contain the following fields, each separated by whitespace:

There are four possible conversion algorithms:

Lines in format B, if present, consist of two hexadecimal numbers, prefixed with 0x, separated by whitespace. The first of these is a foreign character code which has multiple equivalents in Unicode (according to the data in the source file), and the second is the code of the preferred Unicode character to which the foreign character should be converted.


The Unicode-to-foreign data

This section is structured similarly to the foreign-to-Unicode data section. It is contained within the following lines:

StartUnicodeToForeignData

EndUnicodeToForeignData

In between these two lines are one or more lines in format C (defined below). These may be optionally followed by one or more of lines in format D (defined below), in which case the lines in format C and format D are separated by the line:

ConflictResolution

Format C is very similar to format A with one exception, which is an additional field to specify the size of the output character code in bytes (as this is a foreign character code). Each line in format C indicates the conversion algorithm to be used for a particular range of Unicode character codes. Lines in format C contains the following fields, each separated by whitespace:

Format D is analogous to format B (described above). Like format B, it consists of two hexadecimal numbers prefixed with 0x, separated by whitespace. However, the first of these is a Unicode character code which has multiple equivalents in the foreign character set (according to the data in the source file), and the second is the code of the preferred foreign character to which the Unicode character should be converted.


Generating multiple SCnvConversionData data structures

It is sometimes desirable for further objects to be generated which provide a view of a subset of the main SCnvConversionData object. This is possible by inserting an extra pair of lines of the following form in both the foreign-to-Unicode data and the Unicode-to-foreign data sections in the control file:

StartAdditionalSubsetTable <name-of-SCnvConversionData-object>

EndAdditionalSubsetTable <name-of-SCnvConversionData-object>

These lines should be placed around the block of lines to be included in the named SCnvConversionData object. Note that only one pair of these lines can occur in each of the foreign-to-Unicode data and the Unicode-to-foreign data sections, and if a pair occurs in one, it must also occur in the other. Accessing one of these SCnvConversionData objects from handwritten C++ files is done by putting a line of the following form at the top of the relevant C++ file.

GLREF_D const SCnvConversionData <name-of-SCnvConversionData-object>;

The named object can then be used as required.

Using this technique means that two (or more) foreign character sets where one is a subset of the other(s) can share the same conversion data. This conversion data would need to be in a shared-library DLL which the two (or more) plug-in DLLs would both link to.


Choosing an appropriate algorithm for a range of character codes

Of the four conversion algorithms listed above, the keyed table is the most general and can be used for any foreign character set. However, it is the algorithm requiring the most storage space, as well as being the slowest (a binary search is required), therefore it is best avoided if possible. The indexed table also requires storage space (although less than the keyed table), but is much faster. The direct and offset algorithms are the fastest and require negligible storage. It is thus necessary to choose appropriate algorithms to minimize storage and to maximize speed of conversion.

Ranges of characters in the control file are permitted to overlap. This is useful as it means that a keyed table whose range is the entire range of the foreign character set (or the Unicode character set) can be used at the end of the foreign-to-Unicode data (or Unicode-to-foreign data) to catch all the characters that were not caught by the preceding ranges, which will have used better algorithms.

[Top]


Running cnvtool

Invoke cnvtool on the source and control files to generate a cpp file that implements the interface defined by convgeneratedcpp.h. For information on the syntax for invoking cnvtool, see cnvtool command syntax.

[Top]


Implementing the plug-in DLL interface

The plug-in DLL interface is defined in convplug.h. The cpp file which implements this interface should #include convgeneratedcpp.h so that it can access the two (const) global objects implemented in the cnvtool-generated cpp file. The SCnvConversionData object is useful for implementing the second and third functions of the plug-in DLL interface (ConvertFromUnicode() and ConvertToUnicode()). This is because the CCnvCharacterSetConverter class provides some static functions taking SCnvConversionData parameters (DoConvertFromUnicode() and DoConvertToUnicode()). These utility functions make the implementation of the second and third functions of the plug-in interface trivial for non-complex character sets.

All eleven functions prototyped in convplug.h need to be implemented by the plug-in DLL. The implementations of the reserved functions should do nothing, i.e. have empty function bodies.

The implementations of ConvertFromUnicode() and ConvertToUnicode() must fulfil the following behavioural requirements. They must return either a negative error code (see CCnvCharacterSetConverter::TError), or the number of elements at the end of the input descriptor which have not been converted, either because the output descriptor is full, or because there is a truncated sequence at the end of the input descriptor, e.g. only the first half of a Unicode surrogate pair, or only the first byte of a multi-byte foreign character set character code, or a truncated escape sequence of a modal foreign character set. The functions should be able to cope with the situation where the output descriptor is too short or if there is a truncated sequence at the end of the input descriptor, without returning an error, although if the input descriptor consists purely of a truncated sequence, they should return CCnvCharacterSetConverter::EErrorIllFormedInput.

The CnvUtilities class provides some other utility functions which are of use for more complex foreign character sets, for instance modal character sets. Modal character sets are those where the interpretation of a given byte of data is dependent on the current mode, mode changing being performed by certain defined escape sequences which occur in the byte stream.

[Top]


The mmp file

The mmp file used to build the plug-in DLL should specify the targetpath, targettype, uid and deffile keywords as follows:

targetpath        \system\charconv
targettype        dll
uid                0x1000601a 0x<UID-in-hexadecimal>
#if defined(WINS)
deffile            \epoc32\release\wins\CONVPLUG.DEF
#elif defined(MARM)
deffile            \epoc32\release\marm\CONVPLUG.DEF
#else
error
#endif

The second of the two UIDs (Universal Identifiers) specified in the .mmp file must be a unique number allocated by Symbian specifically for the required foreign character set. It should be requested in the normal way for UIDs (by email to the Symbian Developer Network). The first UID should always have the value 0x1000601a.