--- a/uiutils/Findutil/src/FindUtilKorean.cpp Thu Jul 15 18:56:19 2010 +0300
+++ b/uiutils/Findutil/src/FindUtilKorean.cpp Thu Aug 19 10:11:06 2010 +0300
@@ -17,6 +17,11 @@
#include "FindUtilKorean.h"
+#include <e32svr.h>
+
+#ifdef _DEBUG
+#include <charconv.h>
+#endif
const TInt KSBase = 0xac00; // base address for hangul syllables
const TInt KLBase = 0x1100; // base address for L-jamo
@@ -93,8 +98,48 @@
0x1175,
};
+const TUint16 conversionTableFromLJamoToCompatibilityJamo[] = {
+0x3131, /* ? */
+0x3132, /* ? */
+0x3134, /* ? */
+0x3137, /* ? */
+0x3138, /* ? */
+0x3139, /* ? */
+0x3141, /* ? */
+0x3142, /* ? */
+0x3143, /* ? */
+0x3145, /* ? */
+0x3146, /* ? */
+0x3147, /* ? */
+0x3148, /* ? */
+0x3149, /* ? */
+0x314A, /* ? */
+0x314B, /* ? */
+0x314C, /* ? */
+0x314D, /* ? */
+0x314E /* ? */
+};
+
#define KCCount (sizeof(conversionTableFromCompatibilityJamoToJamo) / sizeof(TUint16))
+#define KCountCompToJamo (sizeof(conversionTableFromCompatibilityJamoToJamo) / sizeof(TUint16))
+
+#define KCountLJamoToComp (sizeof(conversionTableFromLJamoToCompatibilityJamo) / sizeof(TUint16))
+
+#define ISLJamo(a) (KLBase <= a && a <= KLBase + KLCount)
+
+#define IsCompatibilityJamo(a) (0x3130 <= a && a <= 0x318F)
+
+const TInt KNextCharsGranuarity = 20;
+
+const TUid KUidPhoneBook = {0x101F4CCE};
+const TUid KUidPhoneBookServer = {0x10207277};
+const TUid KUidSymbianContactModel = {0x10003A73};
+
+#define IsPhoneBookProcess(a) ( a == KUidSymbianContactModel || a == KUidPhoneBook || a == KUidPhoneBookServer )
+
+
+
// ============================ MEMBER FUNCTIONS =============================
@@ -117,6 +162,13 @@
//
void CFindUtilKorean::ConstructL()
{
+#ifdef _DEBUG
+ User::LeaveIfError( iFs.Connect() );
+ iConv = CCnvCharacterSetConverter::NewL();
+ iConv->PrepareToConvertToOrFromL(0x200100FF, iFs);
+#endif
+
+ iCurrentProcessUid3 = ( RProcess().Type() )[2];
}
// ---------------------------------------------------------------------------
@@ -133,6 +185,10 @@
//
CFindUtilKorean::~CFindUtilKorean()
{
+#ifdef _DEBUG
+ delete iConv;
+ iFs.Close();
+#endif
}
// ---------------------------------------------------------------------------
@@ -156,35 +212,140 @@
// Compares two strings against others.
// ---------------------------------------------------------------------------
//
-TBool CFindUtilKorean::IsFindMatchL(
- const TDesC& aItemString,
- const TDesC& aSearchText )
+TInt CFindUtilKorean::IsFindMatch(
+ const TDesC& aItemString,
+ const TDesC& aSearchText,
+ const TMatchFlag aFlag)
{
- TBool result( EFalse );
+
+#ifdef _DEBUG
+ TRAP_IGNORE(
+ HBufC8* bufItemString = HBufC8::NewLC((aItemString.Length() + 1) * 2);
+ HBufC8* bufSearchText = HBufC8::NewLC((aSearchText.Length() + 1) * 2);
+ TPtr8 ptrItemString(bufItemString->Des());
+ ptrItemString.FillZ(ptrItemString.MaxLength());
+ TPtr8 ptrSearchText(bufSearchText->Des());
+ ptrSearchText.FillZ(ptrSearchText.MaxLength());
+ iConv->ConvertFromUnicode(ptrItemString, aItemString);
+ iConv->ConvertFromUnicode(ptrSearchText, aSearchText);
+ RDebug::Printf("DBG: comparing %s, %s", bufItemString->Ptr(), bufSearchText->Ptr());
+ CleanupStack::PopAndDestroy(2);
+ );
+#endif
// To disable the wildchar matching provided by MatchC.
- if ( KErrNotFound != aSearchText.Locate( KLitQuestion ) &&
+ if ( aFlag == EMatchFlagNone &&
+ KErrNotFound != aSearchText.Locate( KLitQuestion ) &&
KErrNotFound != aSearchText.Locate( KLitStar ) )
{
- return EFalse;
+#ifdef _DEBUG
+ RDebug::Printf("DBG: comparing includes wild");
+#endif
+ return KErrNotFound;
}
-
+
+#if 1 // 2009.08.14 consonent based search
+ TUint flag = aFlag;
+
+ TInt lenItemString = aItemString.Length();
+ TInt lenSearchText = aSearchText.Length();
+
+ // detect asterik in end of string
+ if (lenSearchText > 0 && aSearchText[lenSearchText - 1] == KLitStar)
+ {
+ flag |= EMatchFlagAsterikInLast;
+ lenSearchText--;
+ }
+
+ // set asterik start
+ if (!IsPhoneBookProcess(iCurrentProcessUid3) ||
+ (aSearchText.Length() > 0 && aSearchText[0] == KLitStar))
+ {
+ flag |= EMatchFlagAsterikInStart;
+ }
+
+ if (lenItemString < lenSearchText)
+ {
+ return KErrNotFound;
+ }
+
+ if (IsPhoneBookProcess(iCurrentProcessUid3))
+ {
+ TInt i = 0;
+ TInt j = 0;
+ for (; i < lenItemString && j < lenSearchText; i++)
+ {
+ TChar ch(aItemString[i]);
+ if (IsFindWordSeparator(ch))
+ {
+ continue;
+ }
+
+ if (MatchConsonentBased(ch, aSearchText[j]))
+ {
+ j++;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ if (j == lenSearchText)
+ return 0;
+ }
+
+ for (TInt i = 0; i < lenItemString - lenSearchText + 1; i++)
+ {
+ if (!(flag & EMatchFlagAsterikInStart))
+ {
+ if (0 != i && !IsFindWordSeparator(aItemString[i - 1]))
+ {
+ continue;
+ }
+ }
+
+ TBool matched(ETrue);
+ for (TInt j = 0; j < lenSearchText; j++)
+ {
+ if (!MatchConsonentBased(aItemString[i + j], aSearchText[j]))
+ {
+#ifdef _DEBUG
+ RDebug::Printf("DBG: mismatch between %d %d", i + j, j);
+#endif
+ matched = EFalse;
+ break;
+ }
+ }
+
+ if (matched)
+ {
+#ifdef _DEBUG
+ RDebug::Print(_L("DBG: comparing matched"));
+#endif
+ return i;
+ }
+ }
+
+ return KErrNotFound;
+
+#else
// Convert aItemString to single jamo's.
HBufC* itemString = HBufC::NewLC( aItemString.Length() * KMaxLengthDecomposedSyllable );
DecomposeToPlainJamos( aItemString, itemString );
-
+
HBufC* searchText = HBufC::NewLC( aSearchText.Length() * KMaxLengthDecomposedSyllable + 2 );
searchText->Des().Append( KLitStar );
// Convert aSearchText to single jamo's.
DecomposeToPlainJamos( aSearchText, searchText );
searchText->Des().Append( KLitStar );
-
+
// Compare strings containing plain jamo's against others.
for ( TInt i = 0; i < itemString->Length() && !result; i++ )
{
- if ( 0 == i || IsFindWordSeparator(
- static_cast<TChar>( itemString->Des()[ i - 1 ] ) ) )
+ if ( 0 == i || IsFindWordSeparator(
+ static_cast<TChar>( itemString->Des()[ i - 1 ] ) ) )
{
if ( KErrNotFound != itemString->Mid( i ).MatchC( *searchText ) )
{
@@ -192,11 +353,12 @@
}
}
}
-
+
CleanupStack::PopAndDestroy( searchText );
CleanupStack::PopAndDestroy( itemString );
-
- return result;
+
+ return result;
+#endif
}
// ---------------------------------------------------------------------------
@@ -230,6 +392,25 @@
}
}
+void CFindUtilKorean::DecomposeChar( TChar aChar, TDes& aDecomposedString )
+ {
+ aDecomposedString.Zero();
+ if ( IsHangulSyllable( aChar ) )
+ {
+ Decompose( aChar, aDecomposedString );
+ }
+ else if ( IsHangulCompatibilityJamo( aChar ) )
+ {
+ TUint16 jamo = conversionTableFromCompatibilityJamoToJamo[ (TInt)aChar - KCBase ];
+ aDecomposedString.Append( jamo );
+ }
+ // Otherwise append character directly to 'decomposed string'.
+ else
+ {
+ aDecomposedString.Append( aChar );
+ }
+ }
+
// ---------------------------------------------------------------------------
// Decomposes hangul syllables to single jamos.
// ---------------------------------------------------------------------------
@@ -285,7 +466,7 @@
{
// Character is 'hangul compatibility jamo'
// if it's numeric value is between KCBase and KCBase + KCCount.
- TInt index = static_cast<TInt> ( aChar ) - KCBase;
+ TInt index = static_cast<TInt>( aChar ) - KCBase;
if ( index < 0 || index >= KCCount )
{
return EFalse;
@@ -304,20 +485,17 @@
// does not contain any characters.
if ( aContactsField.Length() )
{
- // In case that both of strings contain some characters,
- // matching is made with function below.
- TRAPD(err, retVal = IsFindMatchL( aContactsField, aWord ));
-
- if (err != KErrNone)
- {
- retVal = EFalse;
- }
+ // In case that both of strings contain some characters,
+ // matching is made with function below.
+#ifdef _DEBUG
+ RDebug::Printf("DBG: Comparing from Match");
+#endif
+ retVal = (IsFindMatch( aContactsField, aWord ) != KErrNotFound);
}
- return retVal;
+ return retVal;
}
-
// ---------------------------------------------------------------------------
// It tests a partial matching.
// ---------------------------------------------------------------------------
@@ -342,7 +520,11 @@
// In case that both of strings contain some characters,
// matching is made with function below.
- return IsFindMatchL( aItemString, aSearchText );
+#ifdef _DEBUG
+ RDebug::Printf("DBG: Comparing from MatchRefineL");
+#endif
+
+ return (IsFindMatch( aItemString, aSearchText ) != KErrNotFound);
}
// -----------------------------------------------------------------------------
@@ -350,19 +532,276 @@
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
-TBool CFindUtilKorean::MatchAdaptiveRefineL( const TDesC& /*aItemString*/,
- const TDesC& /*aSearchText*/, HBufC*& /*aNextChars*/ )
- {
- return 0;
- }
+TBool CFindUtilKorean::MatchAdaptiveRefineL(const TDesC& aItemString,
+ const TDesC& aSearchText, HBufC*& aNextChars)
+ {
+ if (aSearchText.Length() == 0)
+ {
+ TakeIntoNextCharsL(aNextChars, aItemString[0]);
+ return ETrue;
+ }
+ else
+ {
+ const TInt lenItemString = aItemString.Length();
+ const TInt lenSearchText = aSearchText.Length();
+
+ if (lenItemString < lenSearchText)
+ {
+ return EFalse;
+ }
+
+#ifdef _DEBUG
+ RDebug::Printf("DBG: Comparing from MatchAdaptiveRefineL");
+#endif
+ TInt idx = IsFindMatch(aItemString, aSearchText,
+ EMatchFlagAsterikInLast);
+
+ if (idx == KErrNotFound)
+ {
+ return EFalse;
+ }
+
+ TLex lexItemString(aItemString);
+ if (IsPhoneBookProcess(iCurrentProcessUid3) && idx == 0)
+ {
+ // find out the position next to last matched string.
+ // work through strings when it reaches length of search string,
+ // while skipping spaces due to ingnoring space matching scheme.
+ for (TInt compareCount = 0; compareCount < lenSearchText;)
+ {
+ if (!IsFindWordSeparator(lexItemString.Get()))
+ {
+ compareCount++;
+ }
+ }
+
+ if (lexItemString.Eos())
+ return EFalse;
+
+ // Skip spaces
+ while (IsFindWordSeparator(lexItemString.Peek()))
+ {
+ lexItemString.Inc();
+ }
+
+ if (lexItemString.Eos())
+ {
+ return EFalse;
+ }
+ }
+ else
+ {
+ lexItemString.Inc(idx + lenSearchText);
+ }
+
+ TChar next = lexItemString.Peek();
+ if (next == 0)
+ {
+ // nothing to take
+ }
+ else
+ {
+ TakeIntoNextCharsL(aNextChars, next);
+ }
+ }
+
+ return ETrue;
+ }
+
+void CFindUtilKorean::TakeIntoNextCharsL(HBufC*& aNextChars,
+ TChar aCharToInsert)
+ {
+ // examine the characters to be inserted
+ TBuf<3> jamo;
+ if (IsHangulSyllable(aCharToInsert))
+ {
+ Decompose(aCharToInsert, jamo);
+ }
+ else if (IsHangulCompatibilityJamo(aCharToInsert))
+ {
+ TUint16 ljamo =
+ conversionTableFromCompatibilityJamoToJamo[(TInt)aCharToInsert - KCBase];
+ jamo.Append(ljamo);
+ }
+ else
+ {
+ aCharToInsert.UpperCase();
+ }
+
+ TPtr nextChar(aNextChars->Des());
+ TBool reAlloced(EFalse);
+
+ // in case there is no character in the list
+ if (nextChar.Length() == 0)
+ {
+ __ASSERT_ALWAYS(nextChar.MaxLength() > 2, User::Panic(_L("FINDUTIL"), __LINE__));
+
+ // Hangul only
+ if (jamo.Length() && ISLJamo(jamo[0]))
+ {
+ const TChar consonentToInsert =
+ conversionTableFromLJamoToCompatibilityJamo[jamo[0] - KLBase];
+
+ InsertNextCharsL(aNextChars, reAlloced, consonentToInsert);
+
+ // if Jamo only character, return...
+ if (jamo.Length() == 1)
+ {
+ return;
+ }
+ }
+
+ InsertNextCharsL(aNextChars, reAlloced, aCharToInsert);
+ return;
+ }
+
+ TBool jamoInserted(EFalse);
+ TInt length = nextChar.Length();
+ const TBool isPB(IsPhoneBookProcess(iCurrentProcessUid3));
+
+ for (TInt i = 0; i < length; i++)
+ {
+ const TChar ch = nextChar[i];
+ // Hangul consonent check
+ if (!jamoInserted && jamo.Length() && ISLJamo(jamo[0]))
+ {
+ const TChar consonentToInsert =
+ conversionTableFromLJamoToCompatibilityJamo[jamo[0] - KLBase];
+
+ if (ch == consonentToInsert)
+ {
+ // Jamo only character finished
+ if (jamo.Length() == 1)
+ {
+ return;
+ }
+
+ jamoInserted = ETrue;
+ }
+ else if ((isPB && !IsCompatibilityJamo(ch)) || (ch > consonentToInsert))
+ {
+ InsertNextCharsL(aNextChars, reAlloced, consonentToInsert, i);
+ // Jamo only character finished
+ if (jamo.Length() == 1)
+ {
+ return;
+ }
+
+ jamoInserted = ETrue;
+ }
+ else
+ {
+ // pass
+ }
+ }
+ // Hangul or Latin
+ else
+ {
+ if (ch == aCharToInsert)
+ {
+ return; // already exist
+ }
+ else if (isPB && IsCompatibilityJamo(ch))
+ {
+ // pass
+ }
+ else if (ch > aCharToInsert)
+ {
+ InsertNextCharsL(aNextChars, reAlloced, aCharToInsert, i);
+ return; // finished
+ }
+ else
+ {
+ // pass
+ }
+ }
+
+ if (reAlloced)
+ {
+ nextChar.Set(aNextChars->Des());
+ length = nextChar.Length();
+ }
+ }
+
+ InsertNextCharsL(aNextChars, reAlloced, aCharToInsert);
+ }
+
+void CFindUtilKorean::InsertNextCharsL(HBufC*& aNextChars, TBool& aReAlloced,
+ const TChar& aChar, const TInt aIndex)
+ {
+ aReAlloced = EFalse;
+ TPtr ptr(aNextChars->Des());
+ const TInt len = ptr.Length();
+ const TInt maxLen = ptr.MaxLength();
+
+ if (KErrNotFound != ptr.Locate(aChar))
+ {
+ // Do not insert duplicate characters
+ return;
+ }
+
+ if (len == maxLen)
+ {
+ aNextChars = aNextChars->ReAllocL(maxLen + KNextCharsGranuarity);
+ ptr.Set(aNextChars->Des());
+ aReAlloced = ETrue;
+
+#ifdef _DEBUG
+ RDebug::Printf("DBG: Next Character buffer created with %d",
+ ptr.MaxLength());
+#endif
+ }
+
+ if (aIndex == KErrNotFound)
+ {
+ ptr.Append(aChar);
+ }
+ else
+ {
+ TBuf<1> buf;
+ buf.Append(aChar);
+ ptr.Insert(aIndex, buf);
+ }
+ }
// ---------------------------------------------------------------------------
// It checks whether aWord is valid.
// ---------------------------------------------------------------------------
//
-TBool CFindUtilKorean::IsWordValidForMatching( const TDesC& /*aWord*/ )
+TBool CFindUtilKorean::IsWordValidForMatching(const TDesC& /*aWord*/)
{
return ETrue;
}
+TBool CFindUtilKorean::MatchConsonentBased(const TChar& aA, const TChar& aB)
+ {
+ TBuf<3> jamoItemString;
+ TBuf<3> jamoSearchText;
+ DecomposeChar(aA, jamoItemString);
+ DecomposeChar(aB, jamoSearchText);
+ const TInt lenJamoItemString = jamoItemString.Length();
+ const TInt lenJamoSearchText = jamoSearchText.Length();
+
+ // check consonent match for one character
+ if (lenJamoSearchText == 1 &&
+ ISLJamo(jamoItemString[0]) && ISLJamo(jamoSearchText[0]))
+ {
+ if (jamoItemString[0] == jamoSearchText[0])
+ {
+ return ETrue;
+ }
+ }
+ else
+ {
+ TChar chItemString(aA);
+ TChar chSearchText(aB);
+ chItemString.UpperCase();
+ chSearchText.UpperCase();
+ if (chItemString == chSearchText)
+ {
+ return ETrue;
+ }
+ }
+ return EFalse;
+ }
// End of file