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