charconvfw/JPLangUtil/src/jplangutil.cpp
branchRCL_3
changeset 55 336bee5c2d35
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/charconvfw/JPLangUtil/src/jplangutil.cpp	Wed Sep 01 12:39:40 2010 +0100
@@ -0,0 +1,774 @@
+/*
+* Copyright (c) 2002 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+*     A utility for providing Japanese Language-specific (UNICODE) functions.
+*
+*
+*/
+
+
+// INCLUDES FILES
+#include "jplangutil.h"
+#include "jplangutil.tables.h"
+
+// LOCAL DEFINES
+
+// LOCAL CONSTANTS AND ENUMS
+
+#if defined(_DEBUG)
+_LIT( KJPLangUtilPanic, "JPLangUtil" );
+enum TJPLangUtilPanicCodes
+    {
+    EErrNotKatakana = 0x777,
+    EErrNotVoicedKatakana
+    };
+#endif
+
+enum TConvDirection
+    {
+    EHalfToFullWidth,
+    EFullToHalfWidth
+    };
+
+const TInt KHalfWidthKatakanaRange = 59;
+const TInt KHalfWidthIndex = 0;
+const TInt KFullWidthIndex = 1;
+const TInt KFullWidthVoicableKatakanaRange = 23;
+const TInt KFullWidthSemiVoicableKatakanaRange = 5;
+const TInt KHalfWidthSpecialCharRange = 21;
+
+const TText KHalfWidthKatakanaVoicedSoundMark     = 0xff9e;
+const TText KHalfWidthKatakanaSemiVoicedSoundMark = 0xff9f;
+
+// The following Full-width (semi-)voiced markers are
+// *also* considered Hiragana, per Unicode spec.
+const TText KFullWidthKatakanaVoicedSoundMark     = 0x309b;
+const TText KFullWidthKatakanaSemiVoicedSoundMark = 0x309c;
+
+const TText KHalfWidthKatakanaLowerBound = 0xff65;
+const TText KHalfWidthKatakanaUpperBound = 0xff9f;
+const TText KFullWidthKatakanaLowerBound = 0x30a0;
+const TText KFullWidthKatakanaUpperBound = 0x30ff;
+
+const TText KCJKUnifiedIdiographLowerBound = 0x4e00;
+const TText KCJKUnifiedIdiographUpperBound = 0x9fa5;
+const TText KCJKUnifiedIdeographExtALowerBound = 0x3400;
+const TText KCJKUnifiedIdeographExtAUpperBound = 0x4dbf;
+
+const TText KHalfToFullWidthASCIIOffset = 0xfee0;
+const TText KHalfWidthASCIILowerBound = 0x0021; // Leaves out space (0x0020)
+const TText KHalfWidthASCIIUpperBound = 0x007e;
+const TText KFullWidthASCIILowerBound = 0xff01;
+const TText KFullWidthASCIIUpperBound = 0xff5e;
+
+const TUint KFullWidthHiraganaSmallA = 0x3041;
+const TUint KFullWidthHiraganaVU = 0x3094;
+const TUint KFullWidthHiraganaU = 0x3046;
+const TUint KFullWidthHiraganaVoicedSound = 0x309B;
+const TUint KFullWidthKatakanaSmallA = 0x30a1;
+const TUint KFullWidthKatakanaSmallVU = 0x30F4;
+
+
+// ============================== LOCAL CLASSES ================================
+
+/**
+ *  This is an internal utility class used by the JPLangUtil class
+ *  and is intended for encapsulation only.
+ *
+ *  @lib JPLangUtil.lib
+ *  @since 2.6
+ */
+class UnicodeTextUtil
+    {
+    public: // Query Functions
+
+        /**
+        * Determines if aUnicodeChar is a base Katakana that is capable
+        * of being converted into either a Vioced or Semi-voiced Full-width
+        * Katakana character.
+        * If aSemiVoiced is true, then the check is only performed
+        * for Semi-voiced conversion capability.
+        *
+        * @param aUnicodeChar The character to be tested.
+        * @param aSemiVoiced  Whether or not the character is to be tested
+        *                     as convertable to a Semi-voiced Full-width
+        *                     Katakana, rather than just voiced.
+        *
+        * @return ETrue is the character is in fact convertable to either
+        *         a voiced or semi-voiced fullwidth katakana character,
+        *         depending on the aSemiVoiced flag.
+        */
+        static TBool IsFullWidthVoicedConvertableHalfWidthBaseKatakana
+                             ( TText aUnicodeChar, TBool aSemiVoiced = EFalse );
+
+        /**
+        * Determines if aUnicodeChar is a  Vioced or Semi-voiced Full-width
+        * Katakana character.
+        * If aSemiVoiced is true, then the check is only performed
+        * for Semi-voiced.
+        *
+        * @param aUnicodeChar The character to be tested.
+        * @param aSemiVoiced  Whether or not the character is a Semi-voiced
+        *                     Full-width Katakana, rather than just voiced.
+        *
+        * @return ETrue is the character is in fact a voiced or semi-voiced
+        *         fullwidth katakana character, depending on the aSemiVoiced
+        *         flag.
+        */
+        static TBool IsFullWidthVoicedKatakana( TText aUnicodeChar,
+                                                TBool aSemiVoiced = EFalse);
+
+    public: // Conversion Functions
+
+        /**
+        * Converts one Katakana character from either Half to Full-width
+        * or vice versa, depending on the direction specified by aDirection
+        *
+        * @param aDirection Direction to convert.
+        * @param aKatakanaChar The character to convert.
+        *
+        * @return The opposite width Katakana character.
+        */
+        static TChar ConvertKatakanaChar( TConvDirection aDirection,
+                                          TText aKatakanaChar );
+
+        /**
+        * Converts one voiced Katakana character from either Half to Full-width
+        * or vice versa, depending on the direction specified by aDirection,
+        * and appends the converted character to the descriptor aTarget.
+        * In the case that it is from Full to Half-width, it is necessary to
+        * convert it into a base-katakana + (semi-)voiced mark pair, thus
+        * the necessity for passing in the TDes reference return type.
+        * In the case of converting from Half to Full-width, it is only
+        * necessary to pass in a base-katakana that has a (semi-)voiced
+        * Full-width counterpart.
+        *
+        * @param aDirection Direction to convert.
+        * @param aVoicedKatakana The character to convert.
+        * @param aTarget The descriptor to append the converted character(s) to.
+        * @param aSemiVoiced ETrue if performing a Semi-voiced conversion.
+        *                    Default is EFalse.
+        */
+        static void ConvertVoicedKatakanaCharAndAppendToTarget(
+                                                   TConvDirection aDirection,
+                                                   TText aVoicedKatakana,
+                                                   TDes& aTarget,
+                                                   TBool aSemiVoiced = EFalse );
+
+        /**
+        * Converts all special characters *in-place* from either Half to
+        * Full-width or vice versa, depending on the direction specified
+        * by aDirection
+        *
+        * @param aDirection Direction to convert.
+        * @param aUnicodeText The character to convert.
+        *
+        * @return The number of converted special characters.
+        */
+        static TInt ConvertSpecialCharactersInPlace( TConvDirection aDirection,
+                                                     TDes16& aUnicodeText );
+
+        /**
+        * Converts all ASCII *in-place* from either Half to
+        * Full-width or vice versa, depending on the direction specified
+        * by aDirection
+        *
+        * @param aDirection Direction to convert.
+        * @param aUnicodeText The character to convert.
+        *
+        * @return The number of converted ASCII-range characters.
+        */
+        static TInt ConvertASCIIInPlace( TConvDirection aDirection,
+                                         TDes16& aUnicodeText );
+    };
+
+// ============================= LOCAL FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// UnicodeTextUtil::IsFullWidthVoicedConvertableHalfWidthBaseKatakana
+// Determines if aUnicodeChar is a base Katakana that is capable
+// of being converted into either a Vioced or Semi-voiced
+// Full-width character.
+// If aSemiVoiced is true, then the check is only performed
+// for Semi-voiced conversion capability.
+// Returns: ETrue if it is convertable.
+// -----------------------------------------------------------------------------
+//
+TBool UnicodeTextUtil::IsFullWidthVoicedConvertableHalfWidthBaseKatakana
+                                       ( TText aUnicodeChar, TBool aSemiVoiced )
+    {
+    if( aSemiVoiced )
+        {
+        return ( aUnicodeChar >= 0xff8a && aUnicodeChar <= 0xff8e );
+        }
+    else
+        {
+        return ( ( aUnicodeChar == 0xff73 ) ||
+                 ( aUnicodeChar >= 0xff76 && aUnicodeChar <= 0xff7f ) ||
+                 ( aUnicodeChar >= 0xff80 && aUnicodeChar <= 0xff84 ) ||
+                 ( aUnicodeChar >= 0xff8a && aUnicodeChar <= 0xff8e ) ||
+                 ( aUnicodeChar == 0xff9c ) ||
+                 ( aUnicodeChar == 0xff66 ) );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// UnicodeTextUtil::IsFullWidthVoicedKatakana
+// Determines if aUnicodeChar is Full-width Katakana.
+// Returns: ETrue if it is Full-width Katakana.
+// -----------------------------------------------------------------------------
+//
+TBool UnicodeTextUtil::IsFullWidthVoicedKatakana( TText aUnicodeChar,
+                                                  TBool aSemiVoiced )
+    {
+    const TInt voicableRange( aSemiVoiced ?
+                              KFullWidthSemiVoicableKatakanaRange :
+                              KFullWidthVoicableKatakanaRange );
+    const TText* const (*voicedTable) = aSemiVoiced ?
+                              KHalfWidthBaseToFullWidthSemiVoicedKatakanaTable :
+                              KHalfWidthBaseToFullWidthVoicedKatakanaTable;
+    for( TInt i( 0 ); i < voicableRange; ++i )
+        {
+        if( aUnicodeChar == voicedTable[i][KFullWidthIndex] )
+            {
+            return ETrue;
+            }
+        }
+    return EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// UnicodeTextUtil::ConvertKatakanaChar
+// Converts one Katakana Char in the direction specified by aDirection.
+// Assumes aKatakanaChar is within range.
+// Returns: A TText containing either the varient character or the character
+//          itself, in the case there is no conversion.
+// -----------------------------------------------------------------------------
+//
+TChar UnicodeTextUtil::ConvertKatakanaChar( TConvDirection aDirection,
+                                            TText aKatakanaChar )
+    {
+    __ASSERT_DEBUG(
+        JPLangUtil::IsKatakana( aKatakanaChar ) &&
+        !IsFullWidthVoicedKatakana( aKatakanaChar ),
+        User::Panic( KJPLangUtilPanic, EErrNotKatakana )
+    );
+    TChar convChar( aKatakanaChar );
+    const TInt directionIndex( ( aDirection == EHalfToFullWidth ) ?
+                                   KHalfWidthIndex : KFullWidthIndex );
+    for( TInt i( 0 ); i < KHalfWidthKatakanaRange; ++i )
+        {
+        if( aKatakanaChar ==
+                KHalfToFullWidthKatakanaCharTable[i][directionIndex] )
+            {
+            convChar = KHalfToFullWidthKatakanaCharTable[i][!directionIndex];
+            break;
+            }
+        }
+    return convChar;
+    }
+
+// -----------------------------------------------------------------------------
+// UnicodeTextUtil::ConvertVoicedKatakanaChar
+// Converts one Voiced Katakana Char in the direction specified by aDirection,
+// and appends to the descriptor, aTarget.
+// If aSemiVoiced is ETrue, then the code point is converted to the Semi-voiced
+// variant.
+// Assumes aVoicedKatakana is within range.
+// -----------------------------------------------------------------------------
+//
+void UnicodeTextUtil::ConvertVoicedKatakanaCharAndAppendToTarget(
+                                                      TConvDirection aDirection,
+                                                      TText aVoicedKatakana,
+                                                      TDes& aTarget,
+                                                      TBool aSemiVoiced )
+    {
+    __ASSERT_DEBUG(
+        IsFullWidthVoicedConvertableHalfWidthBaseKatakana( aVoicedKatakana ) ||
+        IsFullWidthVoicedKatakana( aVoicedKatakana, aSemiVoiced ),
+        User::Panic( KJPLangUtilPanic, EErrNotVoicedKatakana )
+    );
+
+    const TInt  voicableRange( aSemiVoiced ?
+                               KFullWidthSemiVoicableKatakanaRange :
+                               KFullWidthVoicableKatakanaRange );
+    const TText* const (*voicedTable) = aSemiVoiced ?
+                              KHalfWidthBaseToFullWidthSemiVoicedKatakanaTable :
+                              KHalfWidthBaseToFullWidthVoicedKatakanaTable;
+    if( aDirection == EHalfToFullWidth )
+        {
+        // In the case of Half Width, only the base character is needed for
+        // the conversion
+        for( TInt i( 0 ); i < voicableRange; ++i )
+            {
+            if( aVoicedKatakana == voicedTable[i][KHalfWidthIndex] )
+                {
+                const TChar uniChar( voicedTable[i][KFullWidthIndex] );
+                aTarget.Append( uniChar );
+                break;
+                }
+            }
+        }
+    else
+        {
+        for( TInt i( 0 ); i < voicableRange; ++i )
+            {
+            if( aVoicedKatakana == voicedTable[i][KFullWidthIndex] )
+                {
+                const TChar uniChar( voicedTable[i][KHalfWidthIndex] );
+                aTarget.Append( uniChar );
+                break;
+                }
+            }
+        const TChar voicedSoundMark( aSemiVoiced ?
+                                     KHalfWidthKatakanaSemiVoicedSoundMark :
+                                     KHalfWidthKatakanaVoicedSoundMark );
+        aTarget.Append( voicedSoundMark );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// UnicodeTextUtil::ConvertSpecialCharactersInPlace
+// Converts all special characters in the aUnicodeText descriptor in-place
+// that have both Full and Half-width variants.
+// Conversion occurs in the direction specified by aDirection.
+// Returns: The total number of characters converted.
+// -----------------------------------------------------------------------------
+//
+TInt UnicodeTextUtil::ConvertSpecialCharactersInPlace
+                             ( TConvDirection aDirection, TDes16& aUnicodeText )
+    {
+    TInt totalConverted( 0 );
+    const TInt directionIndex( ( aDirection == EHalfToFullWidth ) ?
+                                 KHalfWidthIndex : KFullWidthIndex );
+    for( TInt i( 0 ); i < aUnicodeText.Length(); ++i )
+        {
+        const TText uniChar( aUnicodeText[i] );
+        for( TInt j( 0 ); j < KHalfWidthSpecialCharRange; ++j )
+            {
+            if( uniChar == KHalfToFullWidthSpecialCharTable[j][directionIndex] )
+                {
+                aUnicodeText[i] =
+                    KHalfToFullWidthSpecialCharTable[j][!directionIndex];
+                totalConverted++;
+                break;
+                }
+            }
+        }
+    return totalConverted;
+    }
+
+// -----------------------------------------------------------------------------
+// UnicodeTextUtil::ConvertASCIIInPlace
+// Converts all ASCII *in-place* from either Half to Full-width or vice versa,
+// depending on the direction specified by aDirection.
+// Returns: The total number of characters converted.
+// -----------------------------------------------------------------------------
+//
+TInt UnicodeTextUtil::ConvertASCIIInPlace( TConvDirection aDirection,
+                                           TDes16& aUnicodeText )
+    {
+    TInt totalConverted( 0 );
+    TText lowerBound( ( aDirection == EHalfToFullWidth ) ?
+                        KHalfWidthASCIILowerBound :
+                        KFullWidthASCIILowerBound );
+    TText upperBound( ( aDirection == EHalfToFullWidth ) ?
+                        KHalfWidthASCIIUpperBound :
+                        KFullWidthASCIIUpperBound );
+    TInt offset( ( aDirection == EHalfToFullWidth ) ?
+                   KHalfToFullWidthASCIIOffset :
+                   -KHalfToFullWidthASCIIOffset );
+    for( TInt i( 0 ); i < aUnicodeText.Length(); ++i )
+        {
+        const TText uniChar( aUnicodeText[i] );
+        if( uniChar >= lowerBound && uniChar <= upperBound )
+            {
+            TText convertedChar( static_cast<TText>( uniChar + offset ) );
+            aUnicodeText[i] = convertedChar;
+            totalConverted++;
+            }
+        }
+    return totalConverted;
+    }
+
+// EXPORTED FUNCTIONS
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// JPLangUtil::ConvertHalfToFullWidth
+// Converts all Half-width conformant text (including ASCII, Special Characters
+// and Katakana) found in aUnicodeSource to their Full-width counterparts and
+// places the resulting text into aUnicodeTarget.
+// (detailed information about the parameters and return values can be found
+//  in the header file)
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TInt JPLangUtil::ConvertHalfToFullWidth( const TDesC16& aUnicodeSource,
+                                                  TDes16& aUnicodeTarget )
+    {
+    TInt totalConverted( 0 );
+    // Special Characters are handled in the Katakana conversion...
+    totalConverted =  ConvertHalfToFullWidthKatakana( aUnicodeSource,
+                                                      aUnicodeTarget );
+    totalConverted += UnicodeTextUtil::ConvertASCIIInPlace( EHalfToFullWidth,
+                                                            aUnicodeTarget );
+    return totalConverted;
+    }
+
+// -----------------------------------------------------------------------------
+// JPLangUtil::ConvertFullToHalfWidth
+// Converts all Full-width conformant text found in aUnicodeSource to their
+// Full-width counterparts and places the resulting text into aUnicodeTarget.
+// Only those characters with existing Half-width variants are converted. There
+// will be a 2-for-1 conversion for each Full-width Voiced and Semi-voiced
+// Katakana character.
+// (detailed information about the parameters and return values can be found in
+// the header file)
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TInt JPLangUtil::ConvertFullToHalfWidth( const TDesC16& aUnicodeSource,
+                                                  TDes16& aUnicodeTarget )
+    {
+    TInt totalConverted( 0 );
+    // Special Characters are handled in the Katakana conversion...
+    totalConverted =  ConvertFullToHalfWidthKatakana( aUnicodeSource,
+                                                      aUnicodeTarget );
+    totalConverted += UnicodeTextUtil::ConvertASCIIInPlace( EFullToHalfWidth,
+                                                            aUnicodeTarget );
+    return totalConverted;
+    }
+
+// -----------------------------------------------------------------------------
+// JPLangUtil::ConvertHalfToFullWidthKatakana
+// Converts Half-width Katakana and Special Character text found in
+// aUnicodeSource to their Full-width counterparts and places the resulting text
+// into aUnicodeTarget.
+// (detailed information about the parameters and return values can be found in
+// the header file)
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TInt JPLangUtil::ConvertHalfToFullWidthKatakana
+                       ( const TDesC16& aUnicodeSource, TDes16& aUnicodeTarget )
+    {
+    TInt totalConverted( 0 );
+    const TInt length( aUnicodeSource.Length() );
+    if( length > aUnicodeTarget.MaxLength() )
+        {
+        return KErrTooBig;
+        }
+    aUnicodeTarget.Zero();
+    for( TInt i( 0 ); i < length; ++i )
+        {
+        const TText uniChar( aUnicodeSource[i] );
+        // Check if the next character is a Half Width Katakana (Semi-)Voiced
+        // Sound Mark and if the current character + the voiced sound mark have
+        // a Full Width counterpart
+        if( i + 1 < length )
+            {
+            const TBool isVoiced(
+            ( UnicodeTextUtil::IsFullWidthVoicedConvertableHalfWidthBaseKatakana
+                  ( uniChar ) &&
+              ( aUnicodeSource[i + 1] == KHalfWidthKatakanaVoicedSoundMark )
+            ) );
+
+            const TBool isSemiVoiced(
+            ( UnicodeTextUtil::IsFullWidthVoicedConvertableHalfWidthBaseKatakana
+                  ( uniChar, ETrue ) &&
+              ( aUnicodeSource[i + 1] == KHalfWidthKatakanaSemiVoicedSoundMark )
+            ) );
+
+            if( isVoiced || isSemiVoiced )
+                {
+                UnicodeTextUtil::ConvertVoicedKatakanaCharAndAppendToTarget(
+                    EHalfToFullWidth,
+                    uniChar,
+                    aUnicodeTarget,
+                    isSemiVoiced
+                );
+                i++; // Skip the (semi-)voice marker
+                totalConverted++;
+                continue;
+                }
+            }
+        // If not, then just convert directly if in range
+        if( uniChar >= KHalfWidthKatakanaLowerBound &&
+            uniChar <= KHalfWidthKatakanaUpperBound )
+            {
+            aUnicodeTarget.Append(
+                UnicodeTextUtil::ConvertKatakanaChar( EHalfToFullWidth,
+                                                      uniChar )
+            );
+            totalConverted++;
+            }
+        // Else this is not Half Width Katakana, so copy directly...
+        else
+            {
+            const TChar uniCharacter( uniChar );
+            aUnicodeTarget.Append( uniCharacter );
+            }
+        }
+
+    // Now handle special characters
+    // This logic may be moved into this function to avoid another
+    // loop over the text.
+    totalConverted +=
+        UnicodeTextUtil::ConvertSpecialCharactersInPlace( EHalfToFullWidth,
+                                                          aUnicodeTarget );
+
+    return totalConverted;
+    }
+
+// -----------------------------------------------------------------------------
+// JPLangUtil::ConvertFullToHalfWidthKatakana
+// Converts Full-width Katakana and Special Character text found in
+// aUnicodeSource to their Half-width counterparts and places the resulting text
+// into aUnicodeTarget. There will be a 2-for-1 conversion for each Full-width
+// Voiced and Semi-voiced Katakana character.
+// (detailed information about the parameters and return values can be found in
+// the header file)
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TInt JPLangUtil::ConvertFullToHalfWidthKatakana
+                       ( const TDesC16& aUnicodeSource, TDes16& aUnicodeTarget )
+    {
+    TInt totalConverted( 0 );
+    const TInt length( aUnicodeSource.Length() );
+    const TInt maxLength( aUnicodeTarget.MaxLength() );
+    if( length > maxLength )
+        {
+        return KErrTooBig;
+        }
+    aUnicodeTarget.Zero();
+    for( TInt i( 0 ); i < length; ++i )
+        {
+        const TText uniChar( aUnicodeSource[i] );
+        // First check if this is this Full Width Katakana
+        if( ( uniChar >= KFullWidthKatakanaLowerBound &&
+              uniChar <= KFullWidthKatakanaUpperBound ) ||
+            ( uniChar == KFullWidthKatakanaVoicedSoundMark ||
+              uniChar == KFullWidthKatakanaSemiVoicedSoundMark ) )
+            {
+            // Then check if it is (Semi-)Voiced and convert it properly
+            const TBool isVoiced(
+                UnicodeTextUtil::IsFullWidthVoicedKatakana( uniChar )
+            );
+            const TBool isSemiVoiced(
+                UnicodeTextUtil::IsFullWidthVoicedKatakana( uniChar, ETrue )
+            );
+            if( isVoiced || isSemiVoiced )
+                {
+                if( aUnicodeTarget.Length() + 2 > maxLength )
+                    {
+                    // This descriptor can't hold the new data
+                    aUnicodeTarget.Zero();
+                    return KErrTooBig;
+                    }
+                UnicodeTextUtil::ConvertVoicedKatakanaCharAndAppendToTarget(
+                    EFullToHalfWidth,
+                    uniChar,
+                    aUnicodeTarget,
+                    isSemiVoiced
+                );
+                totalConverted++;
+                }
+            else
+                {
+                if( aUnicodeTarget.Length() + 1 > maxLength )
+                    {
+                    // This descriptor can't hold the new data
+                    aUnicodeTarget.Zero();
+                    return KErrTooBig;
+                    }
+                aUnicodeTarget.Append(
+                    UnicodeTextUtil::ConvertKatakanaChar(
+                        EFullToHalfWidth,
+                        uniChar
+                    )
+                );
+                totalConverted++;
+                }
+            }
+        // This is not Full Width Katakana, so copy directly...
+        else
+            {
+            if( aUnicodeTarget.Length() + 1 > maxLength )
+                {
+                // This descriptor can't hold the new data
+                aUnicodeTarget.Zero();
+                return KErrTooBig;
+                }
+            const TChar uniCharacter( uniChar );
+            aUnicodeTarget.Append( uniCharacter );
+            }
+        }
+
+    // Now handle special characters
+    // This logic may be moved into this function to avoid another loop over
+    // the text
+    totalConverted +=
+        UnicodeTextUtil::ConvertSpecialCharactersInPlace( EFullToHalfWidth,
+                                                          aUnicodeTarget );
+
+    return totalConverted;
+    }
+
+// -----------------------------------------------------------------------------
+// JPLangUtil::ConvertFullHiragnaToFullKatakana
+// Converts Full-width Hiragana and Special Character text found in
+// aUnicodeSource to their Full-width counterparts and places the
+// resulting text into aUnicodeTarget.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TInt JPLangUtil::ConvertFullHiragnaToFullKatakana
+                       ( const TDesC16& aUnicodeSource, TDes16& aUnicodeTarget )
+    {
+    TInt totalConverted( 0 );
+    const TInt length( aUnicodeSource.Length() );
+    const TInt maxLength( aUnicodeTarget.MaxLength() );
+    if( length > maxLength )
+        {
+        return KErrTooBig;
+        }
+
+    const TUint comp = KFullWidthKatakanaSmallA - KFullWidthHiraganaSmallA;
+
+    aUnicodeTarget.Zero();
+    for( TInt i( 0 ); i < length; ++i )
+        {
+        const TText uniChar( aUnicodeSource[i] );
+        TText uniChar2(0);
+        if (i + 1 < length)
+            {
+            uniChar2 = aUnicodeSource[i+1];
+            }
+        // First check if this is this Full Width Katakana
+        if (KFullWidthHiraganaSmallA <= uniChar && uniChar <= KFullWidthHiraganaVU)
+            {
+            if (uniChar == KFullWidthHiraganaU
+             && uniChar2 == KFullWidthHiraganaVoicedSound)
+                {
+                aUnicodeTarget.Append(KFullWidthKatakanaSmallVU);
+                totalConverted++;
+                i++;
+                }
+            else
+                {
+                TUint katakana = uniChar + comp;
+                if (IsKatakana(katakana))
+                    {
+                    aUnicodeTarget.Append(katakana);
+                    totalConverted++;
+                    }
+                }
+            }
+        else
+            {
+            aUnicodeTarget.Append(uniChar);
+            totalConverted++;
+            }
+        }
+
+    // Now handle special characters
+    // This logic may be moved into this function to avoid another loop over
+    // the text
+    totalConverted +=
+        UnicodeTextUtil::ConvertSpecialCharactersInPlace( EFullToHalfWidth,
+                                                          aUnicodeTarget );
+
+    return totalConverted;
+    }
+
+// -----------------------------------------------------------------------------
+// JPLangUtil::IsKatakana
+// Determines whether or not the character is Katakana
+// (detailed information about the parameters and return values can be found in
+// the header file)
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TBool JPLangUtil::IsKatakana( const TText aUnicodeChar )
+    {
+    return ( ( aUnicodeChar >= KFullWidthKatakanaLowerBound &&
+               aUnicodeChar <= KFullWidthKatakanaUpperBound ) ||
+             ( aUnicodeChar >= KHalfWidthKatakanaLowerBound &&
+               aUnicodeChar <= KHalfWidthKatakanaUpperBound ) ||
+             ( aUnicodeChar == KFullWidthKatakanaVoicedSoundMark ||
+               aUnicodeChar == KFullWidthKatakanaSemiVoicedSoundMark ) );
+    }
+
+// -----------------------------------------------------------------------------
+// JPLangUtil::IsHiragana
+// Determines whether or not the character is Hiragana
+// (detailed information about the parameters and return values can be found in
+// the header file)
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TBool JPLangUtil::IsHiragana( const TText aUnicodeChar )
+    {
+    return ( ( aUnicodeChar >= 0x3041 && aUnicodeChar <= 0x3096 ) ||
+             ( aUnicodeChar >= 0x3099 && aUnicodeChar <= 0x309f ) );
+    }
+
+// -----------------------------------------------------------------------------
+// JPLangUtil::IsKanji
+// Determines whether or not the character is a CJK Unified Ideograph (ExtA)
+// (detailed information about the parameters and return values can be found in
+// the header file)
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TBool JPLangUtil::IsKanji( const TText aUnicodeChar )
+    {
+    return( ( aUnicodeChar >= KCJKUnifiedIdiographLowerBound &&
+              aUnicodeChar <= KCJKUnifiedIdiographUpperBound ) ||
+            ( aUnicodeChar >= KCJKUnifiedIdeographExtALowerBound &&
+              aUnicodeChar <= KCJKUnifiedIdeographExtAUpperBound ) );
+    }
+
+// -----------------------------------------------------------------------------
+// JPLangUtil::IsHalfWidth
+// Determines whether or not the character is UNICODE defined Half-width.
+// (detailed information about the parameters and return values can be found in
+// the header file)
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TBool JPLangUtil::IsHalfWidth( const TText aUnicodeChar )
+    {
+    return // HW Katakana
+           ( ( aUnicodeChar >= 0xff61 && aUnicodeChar <= 0xff9f ) ||
+           // ASCII
+             ( aUnicodeChar >= 0x0020 && aUnicodeChar <= 0x007e ) ||
+           // Special Characters
+             ( aUnicodeChar == 0x00a2 || aUnicodeChar == 0x00a3 ||
+               aUnicodeChar == 0x00a5 || aUnicodeChar == 0x00a6 ||
+               aUnicodeChar == 0x00a9 || aUnicodeChar == 0x00ac ||
+               aUnicodeChar == 0x00af || aUnicodeChar == 0x2985 ||
+               aUnicodeChar == 0x2986 ) ||
+           // HW Symbol Variants
+             ( aUnicodeChar >= 0xffe8 && aUnicodeChar <= 0xffee ) );
+    }
+
+// -----------------------------------------------------------------------------
+// JPLangUtil::IsFullWidth
+// Determines whether or not the character is UNICODE defined Full-width.
+// Essentially, all code values that are not Half-width.
+// (detailed information about the parameters and return values can be found in
+// the header file)
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TBool JPLangUtil::IsFullWidth( const TText aUnicodeChar )
+    {
+        return !IsHalfWidth( aUnicodeChar );
+    }
+
+// End of File