Creating CHARCONV plug-in DLLs
Each CHARCONV plug-in DLL contains the necessary information on how to convert text between Unicode and a particular character set (such as ISO-8859-2, GB-2312-80, etc) - the latter henceforth being referred to as the foreign character set. Creating a plug-in DLL is a two-stage process, as follows:

1.	The CNVTOOL program is run to generate a C++ file from two text files which are known as the source file and the control file.
2.	The generated C++ file is compiled along with another (hand-written) C++ file to produce the DLL.

These source file and the control file are both case insensitive and permit comments beginning with a “#” character and extending to the end of the line. They also permit blank lines and leading and trailing white-space on non-blank lines. 
Using CNVTOOL
CNVTOOL is called from the command-line as follows:

CNVTOOL <control-file> <source-file> <output-C++-file>

It also supports the following flags, which may be positioned anywhere in the parameter list (each has a short and a long form, shown below separated by a ‘|’):

•	-s | -generateSourceCode - this should now always be used. (Not using it will cause CNVTOOL to generate an old-style binary conversion-data file - this is deprecated, although still supported for backwards compatibility.)
•	-c | -columns(<number-of-columns>: <column-of-foreign-character-set-codes>, <column-of-Unicode-codes>) - this should be used if the source file consists of a non-standard number of columns, or if the columns are in a non-standard order (see “The format of the source file” below). “1” (rather than “0”) is the first column. If this flag is not used, then -columns(2: 1, 2) is assumed.
•	-r | -omitReplacementForUnconvertibleUnicodeCharacters - this should be used if the replacement for unconvertible Unicode characters specified in the control file is not actually going to be used by the plug-in DLL. (This flag can only be used if -generateSourceCode is also used.)
•	-p | -cutOutAnyPrivateUseUnicodeCharacterSlotsBeingUsed - if this is not used and one or more private-use Unicode character slots are being used, a warning is generated.
•	-u | -sourceFilesToSubtract(<source-file-1>, <source-file-2>, ...) - this is for use when only a subset of the actual source file is to be used, the conversion pairs contained in the source files listed under this flag being subtracted from the conversion pairs obtained from the actual source file.
The plug-in DLL
The interface
The interface to which the plug-in DLL must conform is defined in \epoc32\include\CONVPLUG.H which should be #include-d into any C++ files implementing the exported functions of this interface. The implementations of the eight reserved functions should do nothing - i.e. have empty function bodies. The MMP file used to build the actual 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 number allocated by Symbian specifically for the required foreign character set. The first UID must have the value 0x1000601a.
Using the data structures generated by CNVTOOL
The C++ file generated by CNVTOOL contains two things: an instance of a SCnvConversionData data structure (this data structure is defined in \epoc32\include\CONVDATA.H), and a function returning a descriptor which is the replacement for unconvertible Unicode characters. These two things can be accessed from hand-written C++ files by #include-ing \epoc32\include\CONVGENERATEDCPP.H. (Note that if the CNVTOOL command-line included the  -omitReplacementForUnconvertibleUnicodeCharacters flag, then the descriptor-returning function cannot be used.)
There are a number of utility functions that can be called by ConvertFromUnicode and ConvertToUnicode. The CCnvCharacterSetConverter class (defined in \epoc32\include\CHARCONV.H) provides the two most basic of these utility functions which are its static member functions DoConvertFromUnicode and DoConvertToUnicode. The CnvUtilities class (defined in \epoc32\include\CONVUTILS.H and whose code is in CONVUTILS.DLL) provides some other utility functions which are of use for more complex foreign character sets, including, among other types of character set, 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.)
Requirements of the behaviour of the two conversion functions
The two conversion functions in the DLL interface (ConvertFromUnicode and ConvertToUnicode) must fulfill the following behavioural requirements. They must return either a negative error code in CCnvCharacterSetConverter::TError or the number of elements and 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 cope without returning an error if the output descriptor is too short or if there is a truncated sequence at the end of the input descriptor, although if the input descriptor consists purely of a truncated sequence, they should return CCnvCharacterSetConverter::EErrorIllFormedInput.
Test code
It is obviously important to write code to test the plug-in DLL. This can be based on some of CHARCONV’s own test code which can be found in \charconv\test\source\main (if access to this source directory is available).
The format of the source file
The format of the source file is relatively straightforward. Each line consists of two hexadecimal numbers separated by white-space, each number being prefixed with 0x. The first number is the encoding of a character in the foreign character set, and the second is the Unicode encoding of the same character.
A number of files in this format are already available from The Unicode Consortium - either from the CD that comes with the book The Unicode Standard, Version 2.0, or from ftp://ftp.unicode.org/Public/MAPPINGS/ (the latter will probably have more up-to-date versions of these files than the former).
In some cases the foreign character codes that appear in these text files 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 of the following format in the source file:

SET_FOREIGN_CHARACTER_CODE_PROCESSING_CODE [Perl-code]

This line affects all lines in the source file beneath it until the next such line. If nothing other than white-space appears after SET_FOREIGN_CHARACTER_CODE_PROCESSING_CODE, the foreign character codes in the subsequent lines are used unprocessed (just as they are if SET_FOREIGN_CHARACTER_CODE_PROCESSING_CODE is not used at all). The Perl code must return a number using the variable $foreignCharacterCode as its input parameter. As an 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;.
The format of the control file
The format of the control file is somewhat more complicated than that of the source file. There are four sections to the control file: the header, the foreign variable-byte data, the foreign-to-Unicode data and the Unicode-to-foreign data.
The format of the header
The header consists of five lines in fixed order. Their format is as follows (alternatives are separated by a |, single space characters represent single or multiple white-space characters):

UID 0x<UID-in-hexadecimal>
Endianness Unspecified|FixedLittleEndian|FixedBigEndian
ReplacementForUnconvertibleUnicodeCharacters <see-below>
ForeignCharacterCodeProcessingCode <see-below>

The value of UID (Universal IDentifier) must be a number allocated by Symbian specifically for the required foreign character set. This may, and should, on pain of a warning being generated, be omitted if -generateSourceCode is used on the CNVTOOL command-line - instead this UID needs to be specified in the MMP file. 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 white-space, 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 foreign to Unicode).
ForeignCharacterCodeProcessingCode is now obsolete and no longer has any effect. It can safely be omitted from the control file. (Using it will generate a warning from the Perl script).
The format of the foreign variable-byte data
This section begins and ends with the following two lines, respectively:

StartForeignVariableByteData
EndForeignVariableByteData

In between these two 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 are separated by white-space. 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. As an example - if the foreign character set uses only a single byte per character and it’s 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 format of the foreign-to-Unicode data
This section begins and ends with the following two lines, respectively:

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. There are four possible conversion algorithms:

1.	direct - this is where each character in the range has the same encoding in Unicode as in the foreign character set,
2.	offset - this is where the offset from the foreign encoding to the Unicode encoding is the same for each character in the range,
3.	indexed table (16) - this is where a contiguous block of foreign character codes maps onto a random collection of Unicode character codes (the 16 refers to the fact that each Unicode character code must use no more than 16 bits),
4.	keyed table (16-16) - this is where a sparse collection of foreign character codes map onto a random collection of Unicode character codes (the 16 refers to the fact that each foreign character code and each Unicode character code must use no more than 16 bits).

Lines in format A contains the following fields, each separated by white-space:

•	include-priority (not currently used) - a decimal number
•	search-priority (not currently used) - a decimal number
•	first input character code in the range - a hexadecimal number prefixed with 0x
•	last input character code in the range - a hexadecimal number prefixed with 0x
•	algorithm - one of Direct|Offset|IndexedTable16|KeyedTable1616
•	parameters - (not applicable to any of the current choice of algorithms) - set this to {}

Format B is two hexadecimal numbers prefixed with 0x, separated by white-space. 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 format of the Unicode-to-foreign data
As will be seen, this section is very similar to the foreign-to-Unicode data. It begins and ends with the following two lines, respectively:

StartUnicodeToForeignData
EndUnicodeToForeignData

In between these two lines are one or more of 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 white-space:

•	include-priority (not currently used) - a decimal number
•	search-priority (not currently used) - a decimal number
•	first input character code in the range - a hexadecimal number prefixed with 0x
•	last input character code in the range - a hexadecimal number prefixed with 0x
•	algorithm - one of Direct|Offset|IndexedTable16|KeyedTable1616
•	size of the output character code in bytes (this was not in format A) - a decimal number
•	parameters - (not applicable to any of the current choice of algorithms) - set this to {}

Format D is exact analogous to Format B (described above). Like Format B, it consists of two hexadecimal numbers prefixed with 0x, separated by white-space. 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 couple of lines of the following form in both the foreign-to-Unicode data and the Unicode-to-foreign data 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, and if a pair occurs in one, it must 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 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 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 as essentially only a pointer dereference is required. 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.
CHARCONV provides another tool in the form of a Perl script to analyse the source file and thus help choose the best algorithms for conversion. To run it, type the following command from the \charconv\data directory:

perl -w ANALYSE.PL <source-file> <output-file> <column>

The output file is essentially a rearrangement of the source file sorted according to the <column> parameter, which is passed 1 to sort on the first “column” of the source file (i.e. to sort each line according to their foreign character codes) and 2 to sort on the second “column” (i.e. to sort each line according to their Unicode character codes). The output file also shows the blocks of characters that are contiguous in the specified column. Under each block is a comment indicating the relationship of the other column to the specified column. This is either “random” or “offset” (with the offset specified). If the output file states that a block has an offset of zero, the direct algorithm can be used for that range of characters. If a block has an offset of non-zero, the offset algorithm can be used for that range of characters. If the output file states that a block has a random mapping, the indexed table algorithm can be used for that range of characters. Where the blocks are too small to warrant an algorithm to themselves (as a general guide, blocks of 5 lines or less are probably too small), the keyed table algorithm needs to be used.
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 in the foreign-to-Unicode data (or Unicode-to-foreign data, respectively) to “catch” all the characters that were not “caught” by the preceding ranges, which will have used better algorithms.