Creating a Charconv Plug-in DLL

This section describes how to create a Charconv plug-in DLL.

Introduction

The flowchart below shows the steps to create a Charconv plug-in DLL.

Procedure

An example is used to explain the procedure for creating a Charconv plug-in DLL. This plug-in converts between the cp850 character set and Unicode.

  1. Create a cnvtool source file using a text editor and save it as, for example d:\charconvfiles\data\cp850.txt. This file contains pairs of hexadecimal numbers. The first number in each pair is the encoding of a character in cp850and the second is the Unicode encoding of the same character.

    ...
    0x00    0x0000    #NULL
    0x01    0x0001    #START OF HEADING
    0x02    0x0002    #START OF TEXT
    0x03    0x0003    #END OF TEXT
    0x04    0x0004    #END OF TRANSMISSION
    0x05    0x0005    #ENQUIRY
    0x06    0x0006    #ACKNOWLEDGE
    ...

    For more information about the syntax of a cnvtool source file, refer to Cnvtool Source File.

  2. Create a cnvtool control file using a text editor and save it as, for example d:\charconvfiles\data\cp850.ctl. This file specifies the conversion algorithms to convert both ways between ranges of characters, and other information.

    Endianness                                                            FixedBigEndian
    ReplacementForUnconvertibleUnicodeCharacters                        0x1a # ASCII "substitute" character - must be a single character, and must be little-endian if the "Endianness" above is "Unspecified", otherwise in the same endianness as specified
    
    StartForeignVariableByteData
    #    FirstInitialByteValueInRange    LastInitialByteValueInRange        NumberOfSubsequentBytes
        0x00                            0xff                            0
    EndForeignVariableByteData
    
    StartForeignToUnicodeData
    #    IncludePriority    SearchPriority    FirstInputCharacterCodeInRange    LastInputCharacterCodeInRange    Algorithm                        Parameters
        2                2                0x00                            0x7f                            Direct                            {}        # ASCII
        1                1                0x80                            0xff                            KeyedTable16OfIndexedTables16    {}        # CP850
    EndForeignToUnicodeData
    
    StartUnicodeToForeignData
    #    IncludePriority    SearchPriority    FirstInputCharacterCodeInRange    LastInputCharacterCodeInRange    Algorithm            SizeOfOutputCharacterCodeInBytes    Parameters
        2                2                0x0000                            0x007f                            Direct                1                                    {}        # ASCII
        1                1                0x00A0                            0x25A0                            KeyedTable1616        1                                    {}        # CP850
    EndUnicodeToForeignData
    

    For more information about the syntax of a cnvtool control file, refer to Cnvtool Control File.

  3. Start a command prompt to run cnvtool on the source and control files as follows:

    cd d:\Symbian\epoc32\tools

    cnvtool.bat -generateSourceCode d:\charconvfiles\data\cp850.txt d:\charconvfiles\data\cp850.ctl d:\charconvfiles\data\g_cp850.cpp

    This process generates a C++ source code file called g_cp850.cpp. It is referred to as the cnvtool -generated cpp file. It contains the SCnvConversionData data structure.

    
    #include <e32std.h>
    #include <CONVDATA.H>
    #include <CONVGENERATEDCPP.H>
    
    #define ARRAY_LENGTH(aArray) (sizeof(aArray)/sizeof((aArray)[0]))
    
    
    _LIT8(KLit8ReplacementForUnconvertibleUnicodeCharacters, "\x1a");
    
    GLDEF_C const TDesC8& ReplacementForUnconvertibleUnicodeCharacters_internal()
        {
        return KLit8ReplacementForUnconvertibleUnicodeCharacters;
        }
    
    LOCAL_D const TUint16 keyedTables16OfIndexedTables16_indexedEntries_foreignToUnicode_1[]=
        {
        0x00c7,
        0x00fc,
    ...
     }
    
    
    LOCAL_D const SCnvConversionData::SOneDirectionData::SRange::UData::SKeyedTable16OfIndexedTables16::SKeyedEntry keyedTables16OfIndexedTables16_keyedEntries_foreignToUnicode_1[]=
        {
            {
            0x80,
            0xff,
            keyedTables16OfIndexedTables16_indexedEntries_foreignToUnicode_1
            }
        };
    
    LOCAL_D const SCnvConversionData::SOneDirectionData::SRange::UData::SKeyedTable1616::SEntry keyedTable1616_unicodeToForeign_1[]=
        {
            {
            0x00a0,
            0xff
            },
    ...
     }
    LOCAL_D const SCnvConversionData::SVariableByteData::SRange foreignVariableByteDataRanges[]=
        {
            {
            0x00,
            0xff,
            0,
            0
            }
        };
    
    ....
    
    GLDEF_D const SCnvConversionData conversionData=
        {
        SCnvConversionData::EFixedBigEndian,
            {
            ARRAY_LENGTH(foreignVariableByteDataRanges),
            foreignVariableByteDataRanges
            },
            {
            ARRAY_LENGTH(foreignToUnicodeDataRanges),
            foreignToUnicodeDataRanges
            },
            {
            ARRAY_LENGTH(unicodeToForeignDataRanges),
            unicodeToForeignDataRanges
            },
        NULL,
        NULL
        };
    
    

    For more information about the command syntax of cnvtool, refer to Cnvtool Command Syntax.

  4. Create a cpp file which implements the CCharacterSetConverterPluginInterface class.

    All of the functions defined in the interface must be implemented by the plug-in DLL. The implementations of ConvertFromUnicode() and ConvertToUnicode() must fulfil the following behavioural requirements:

    • They must return a negative error code (see CCnvCharacterSetConverter::TError), or the number of elements remaining in the input descriptor which have not been converted.

    • They must not return an error when the output descriptor is too short or there is a truncated sequence at the end of the input descriptor.

      • If the output descriptor is full, the input descriptor cannot be fully converted.

      • If the input descriptor ends with a truncated sequence, such as the first half of a Unicode surrogate pair, the first byte of a multi-byte foreign character set character code, or a truncated escape sequence of a modal foreign character set, it cannot be fully converted.

    • If the input descriptor consists purely of a truncated sequence they must return CCnvCharacterSetConverter::EErrorIllFormedInput.

    For non-complex character sets, they can call CCnvCharacterSetConverter::DoConvertFromUnicode() and CCnvCharacterSetConverter::DoConvertToUnicode() functions respectively.

    For complex character sets, for example JIS or Shift-JIS, the CnvUtilities class provides some utility functions.

    To access the two (const) global objects implemented in the cnvtool-generated cpp file, you must include the convgeneratedcpp.h header file. The SCnvConversionData object generated can then be used to implement the ConvertFromUnicode() and ConvertToUnicode() functions.

    Example implementation

    #include <e32std.h>
    #include <charconv.h>
    #include <convgeneratedcpp.h>
    #include <ecom/implementationproxy.h>
    #include <charactersetconverter.h>
    
    class CCP850ConverterImpl : public CCharacterSetConverterPluginInterface
        {
    
    public:
        virtual const TDesC8& ReplacementForUnconvertibleUnicodeCharacters();
    
        virtual TInt ConvertFromUnicode(
            CCnvCharacterSetConverter::TEndianness aDefaultEndiannessOfForeignCharacters, 
            const TDesC8& aReplacementForUnconvertibleUnicodeCharacters, 
            TDes8& aForeign, 
            const TDesC16& aUnicode, 
            CCnvCharacterSetConverter::TArrayOfAscendingIndices& aIndicesOfUnconvertibleCharacters);
    
        virtual TInt ConvertToUnicode(
            CCnvCharacterSetConverter::TEndianness aDefaultEndiannessOfForeignCharacters, 
            TDes16& aUnicode, 
            const TDesC8& aForeign, 
            TInt& aState, 
            TInt& aNumberOfUnconvertibleCharacters, 
            TInt& aIndexOfFirstByteOfFirstUnconvertibleCharacter);
    
        virtual TBool IsInThisCharacterSetL(
            TBool& aSetToTrue, 
            TInt& aConfidenceLevel, 
            const TDesC8& aSample);
    
        static CCP850ConverterImpl* NewL();
        virtual ~CCP850ConverterImpl();
    
    private:
        CCP850ConverterImpl();
    
        };
    
    
    const TDesC8& CCP850ConverterImpl::ReplacementForUnconvertibleUnicodeCharacters()
        {
        return ReplacementForUnconvertibleUnicodeCharacters_internal();
        }
    
    TInt CCP850ConverterImpl::ConvertFromUnicode(
            CCnvCharacterSetConverter::TEndianness aDefaultEndiannessOfForeignCharacters, 
            const TDesC8& aReplacementForUnconvertibleUnicodeCharacters, 
            TDes8& aForeign, 
            const TDesC16& aUnicode, 
            CCnvCharacterSetConverter::TArrayOfAscendingIndices& aIndicesOfUnconvertibleCharacters)
        {
        return CCnvCharacterSetConverter::DoConvertFromUnicode(conversionData, aDefaultEndiannessOfForeignCharacters, aReplacementForUnconvertibleUnicodeCharacters, aForeign, aUnicode, aIndicesOfUnconvertibleCharacters);
        }
    
    TInt CCP850ConverterImpl::ConvertToUnicode(
            CCnvCharacterSetConverter::TEndianness aDefaultEndiannessOfForeignCharacters, 
            TDes16& aUnicode, 
            const TDesC8& aForeign, 
            TInt& /*aState*/, 
            TInt& aNumberOfUnconvertibleCharacters, 
            TInt& aIndexOfFirstByteOfFirstUnconvertibleCharacter)
        {
        return CCnvCharacterSetConverter::DoConvertToUnicode(conversionData, aDefaultEndiannessOfForeignCharacters, aUnicode, aForeign, aNumberOfUnconvertibleCharacters, aIndexOfFirstByteOfFirstUnconvertibleCharacter);
        }
    
    TBool CCP850ConverterImpl::IsInThisCharacterSetL(
            TBool& aSetToTrue, 
            TInt& aConfidenceLevel, 
            const TDesC8& /*aSample*/)
        {
        aSetToTrue=ETrue;
        aConfidenceLevel=0;
        return EFalse;
        }
    
    CCP850ConverterImpl* CCP850ConverterImpl::NewL()
        {
        CCP850ConverterImpl* self = new(ELeave) CCP850ConverterImpl();
        return self;
        }
    
    CCP850ConverterImpl::~CCP850ConverterImpl()
        {
        }
    
    CCP850ConverterImpl::CCP850ConverterImpl()
        {
        }
    
    const TImplementationProxy ImplementationTable[] = 
        {
            IMPLEMENTATION_PROXY_ENTRY(0x102825AD,    CCP850ConverterImpl::NewL)
        };
    
    EXPORT_C const TImplementationProxy* ImplementationGroupProxy(TInt& aTableCount)
        {
        aTableCount = sizeof(ImplementationTable) / sizeof(TImplementationProxy);
    
        return ImplementationTable;
        } 
    
  5. Create an ECom registry resource file using a text editor.

    102825ac.rss

    #include "ecom/registryinfo.rh"
    
    RESOURCE REGISTRY_INFO theInfo
        {
        dll_uid = 0x102825AC; // UID acquired from Symbian
        interfaces = 
            {
            INTERFACE_INFO
                {
                interface_uid = 0x101F7F1D; // fixed UID for Charconv plug-ins
                implementations = 
                    {
                    IMPLEMENTATION_INFO
                        {
                        implementation_uid = 0x102825AD; // UID acquired from Symbian
                        version_no = 1;
                        display_name = "CP850";
                        default_data = "CP850";
                        opaque_data = "";
                        }
                    };
                }
            };
        }
    
  6. Create an mmp file which is used to build the plug-in DLL.

    TARGET            cp850.dll
    TARGETTYPE        PLUGIN
    
    CAPABILITY        All -Tcb
    
    UID                0x10009D8D 0x102825AC
    VENDORID        0x70000001
    
    SYSTEMINCLUDE    /epoc32/include
    
    SOURCEPATH        ../src/plugins
    SOURCE            cp850.cpp
    
    SOURCEPATH        /epoc32/build/generatedcpp/charconv
    SOURCE            g_cp850.cpp
    
    SOURCEPATH        ../resource
    START RESOURCE    cp850.rss
    TARGETPATH        /resource/charconv
    LANG            sc
    END
    
    START RESOURCE    102825ac.rss
    TARGET            cp850.rsc
    END
    
    LIBRARY            euser.lib
    LIBRARY            charconv.lib
    LIBRARY            ecom.lib
    

Build the plug-in DLL and install it into the \system\charconv\ directory. The DLL is then available to be loaded when CCnvCharacterSetConverter::PrepareToConvertToOrFromL() is invoked.