--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ipsservices/ipssosplugin/src/ipsplgtextsearcher.cpp Thu Dec 17 08:39:21 2009 +0200
@@ -0,0 +1,631 @@
+/*
+* Copyright (c) 2005-2008 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: This file implements class CIpsPlgTextSearcher.
+*
+*/
+
+
+// INCLUDE FILES
+
+#include "emailtrace.h"
+#include "ipsplgheaders.h"
+
+const TUint KKeywordsArrayGranularity = 8;
+const TInt KUnicodeConversionBufferSize = 100;
+
+// ================= MEMBER FUNCTIONS ====================
+
+// ----------------------------------------------------------------------------
+// CIpsPlgTextSearcher::NewL()
+// Symbian OS 2 phased constructor.
+// ----------------------------------------------------------------------------
+//
+CIpsPlgTextSearcher* CIpsPlgTextSearcher::NewL(
+ MIpsPlgTextSearcherObserver& aObserver )
+ {
+ FUNC_LOG;
+ CIpsPlgTextSearcher* self = CIpsPlgTextSearcher::NewLC( aObserver );
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+// ----------------------------------------------------------------------------
+// CIpsPlgTextSearcher::NewLC()
+// Symbian OS 2 phased constructor.
+// ----------------------------------------------------------------------------
+//
+CIpsPlgTextSearcher* CIpsPlgTextSearcher::NewLC(
+ MIpsPlgTextSearcherObserver& aObserver )
+ {
+ FUNC_LOG;
+ CIpsPlgTextSearcher* self =
+ new ( ELeave ) CIpsPlgTextSearcher( aObserver );
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ return self;
+ }
+
+// ----------------------------------------------------------------------------
+// CIpsPlgTextSearcher::CIpsPlgTextSearcher()
+// Performs the first phase of two phase construction.
+// ----------------------------------------------------------------------------
+//
+CIpsPlgTextSearcher::CIpsPlgTextSearcher(
+ MIpsPlgTextSearcherObserver& aObserver )
+ : iObserver( aObserver )
+ {
+ FUNC_LOG;
+ }
+
+// ----------------------------------------------------------------------------
+// CIpsPlgTextSearcher::ConstructL()
+// Performs the second phase construction.
+// ----------------------------------------------------------------------------
+//
+void CIpsPlgTextSearcher::ConstructL()
+ {
+ FUNC_LOG;
+ iSearchKeywords8 =
+ new ( ELeave ) CDesC8ArrayFlat( KKeywordsArrayGranularity );
+ User::LeaveIfError ( iRFs.Connect() );
+ }
+
+// ----------------------------------------------------------------------------
+// CIpsPlgTextSearcher::~CIpsPlgTextSearcher()
+// Destructor
+// ----------------------------------------------------------------------------
+//
+CIpsPlgTextSearcher::~CIpsPlgTextSearcher()
+ {
+ FUNC_LOG;
+ iKeywordSearchStatusArray.Close();
+
+ if( iSearchKeywords8 )
+ {
+ iSearchKeywords8->Reset();
+ delete iSearchKeywords8;
+ }
+
+ iRFs.Close();
+ }
+
+// ----------------------------------------------------------------------------
+// CIpsPlgTextSearcher::SetParametersL()
+// Sets the search parameters for the search.
+// ----------------------------------------------------------------------------
+//
+void CIpsPlgTextSearcher::SetParametersL(
+ const CDesCArray& aKeywords,
+ TIpsPlgCriteriaOperation aOperator,
+ TBool aCaseSensitive,
+ TInt aSearchResultRecommendedSnippetLength )
+ {
+ FUNC_LOG;
+ iHaveParameters = ETrue;
+
+ iSearchKeywords = &aKeywords;
+
+ iOperator = aOperator;
+ iCaseSensitive = aCaseSensitive;
+ iSearchResultRecommendedSnippetLength =
+ aSearchResultRecommendedSnippetLength;
+
+ iKeywordSearchStatusArray.Reset();
+ TInt count( aKeywords.Count() );
+ for ( TInt i(0); i < count; i++ )
+ {
+ TIpsPlgKeywordSearchStatus status;
+ status.iFound = EFalse;
+ status.iFoundAsNthWord = KErrNotFound;
+
+ iKeywordSearchStatusArray.AppendL( status );
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// CIpsPlgTextSearcher::Cleanup()
+// Cleans up internal data. Must be called before each new search is started.
+// Does not clean up the parameters set via SetParametersL.
+// ----------------------------------------------------------------------------
+//
+void CIpsPlgTextSearcher::Cleanup()
+ {
+ FUNC_LOG;
+ TInt count( iKeywordSearchStatusArray.Count() );
+ for ( TInt i(0); i < count; i++ )
+ {
+ iKeywordSearchStatusArray[i].iFound = EFalse;
+ iKeywordSearchStatusArray[i].iFoundAsNthWord = KErrNotFound;
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// CIpsPlgTextSearcher::SearchL()
+// ----------------------------------------------------------------------------
+//
+TBool CIpsPlgTextSearcher::SearchL( const TDesC& aToBeSearchedDes )
+ {
+ FUNC_LOG;
+ __ASSERT_DEBUG( iHaveParameters,
+ User::Panic( KIpsPlgPanicCategory, EIpsPlgNoParameters ) );
+
+ // when aToBeSearchedDes has no data, it can match *
+ if( !aToBeSearchedDes.Length() )
+ {
+ return EFalse;
+ }
+
+ iFirstMatchKeywordCharPos = KErrNotFound;
+
+ TBool found( DoStringCompareWithKeywordsL( aToBeSearchedDes, *iSearchKeywords,
+ iKeywordSearchStatusArray, iOperator, iCaseSensitive ) );
+
+ if ( found )
+ {
+ // Parameters are not used in function
+ iObserver.HitL( KNullDesC, KErrNone, EFalse, EFalse );
+ }
+ return found;
+ }
+
+// ----------------------------------------------------------------------------
+// CIpsPlgTextSearcher::SearchL()
+// ----------------------------------------------------------------------------
+//
+TBool CIpsPlgTextSearcher::SearchL( const TDesC8& aToBeSearchedDes )
+ {
+ FUNC_LOG;
+ __ASSERT_DEBUG( iHaveParameters,
+ User::Panic( KIpsPlgPanicCategory, EIpsPlgNoParameters ) );
+
+ // when aToBeSearchedDes has no data, it can match *
+ if( !aToBeSearchedDes.Length() )
+ {
+ return EFalse;
+ }
+
+ // Create 8 bit versions from the keywords for better efficiency
+ iSearchKeywords8->Reset();
+ TInt count( iSearchKeywords->Count() );
+ for ( TInt i(0); i < count; i++ )
+ {
+ HBufC8* keyword8Bit = ConvertFromUnicodeL( iRFs,
+ iSearchKeywords->MdcaPoint( i ),
+ KCharacterSetIdentifierUtf8 );
+ CleanupStack::PushL( keyword8Bit );
+ iSearchKeywords8->AppendL( *keyword8Bit );
+ CleanupStack::PopAndDestroy( keyword8Bit );
+ }
+
+ iFirstMatchKeywordCharPos = KErrNotFound;
+
+ TBool found( DoStringCompareWithKeywordsL( aToBeSearchedDes, *iSearchKeywords8,
+ iKeywordSearchStatusArray, iOperator, iCaseSensitive ) );
+
+ if ( found )
+ {
+ // Parameters are not used in function
+ iObserver.HitL( KNullDesC, KErrNone, EFalse, EFalse );
+ }
+ return found;
+ }
+
+// ----------------------------------------------------------------------------
+// CIpsPlgTextSearcher::DoStringCompareWithKeywords()
+// ----------------------------------------------------------------------------
+//
+TBool CIpsPlgTextSearcher::DoStringCompareWithKeywordsL(
+ const TDesC& aToBeSearchedDes,
+ const CDesCArray& aKeywords,
+ RArray<TIpsPlgKeywordSearchStatus>& aKeywordSearchStatusArray,
+ TIpsPlgCriteriaOperation aOperator,
+ TBool aCaseSensitive )
+ {
+ FUNC_LOG;
+ // Compare the string will all the keywords
+ TInt count( aKeywords.Count() );
+ if ( count != aKeywordSearchStatusArray.Count() )
+ {
+ User::Leave( KErrArgument );
+ }
+ for ( TInt i(0); i < count; i++ )
+ {
+ if ( !aKeywordSearchStatusArray[i].iFound ) // keyword not yet found
+ {
+ TInt match;
+ if ( aCaseSensitive )
+ {
+ match = aToBeSearchedDes.Match( aKeywords[i] );
+ }
+ else
+ {
+ match = aToBeSearchedDes.MatchC( aKeywords[i] );
+ }
+
+ // KErrNotFound indicates that no match was found
+ if ( match != KErrNotFound )
+ {
+ aKeywordSearchStatusArray[i].iFound = ETrue;
+ // The 1st found keyword will be also the snippet
+ if ( iFirstMatchKeywordCharPos == KErrNotFound )
+ {
+
+ if ( match == aToBeSearchedDes.Length() )
+ {
+ iFirstMatchKeywordCharPos = 0;
+ }
+ else
+ {
+ iFirstMatchKeywordCharPos = match;
+ }
+
+ }
+
+ if ( aOperator == EIpsPlgCriteriaOperationOR )
+ {
+ // As soon as one keyword is found, the OR search can stop
+ return ETrue;
+ }
+ }
+ }
+ }
+
+ // Check if there is still need to continue searching.
+ TBool keywordsFound;
+ switch ( aOperator )
+ {
+ case EIpsPlgCriteriaOperationAND:
+ keywordsFound = ETrue;
+ break;
+
+ case EIpsPlgCriteriaOperationOR:
+ keywordsFound = EFalse;
+ break;
+
+ default:
+ keywordsFound = ETrue; // to avoid warning
+ break;
+ }
+
+ // For AND search, all keywords must be found, thus if 1 is not found ->
+ // No hit
+ if( aOperator == EIpsPlgCriteriaOperationAND )
+ {
+ for ( TInt j(0); j < count; j++ )
+ {
+ if ( !aKeywordSearchStatusArray[j].iFound )
+ {
+ return EFalse;
+ }
+ }
+ }
+ return keywordsFound;
+ }
+
+// ----------------------------------------------------------------------------
+// CIpsPlgTextSearcher::DoStringCompareWithKeywordsL()
+// ----------------------------------------------------------------------------
+//
+TBool CIpsPlgTextSearcher::DoStringCompareWithKeywordsL(
+ const TDesC8& aToBeSearchedDes,
+ const CDesC8Array& aKeywords,
+ RArray<TIpsPlgKeywordSearchStatus>& aKeywordSearchStatusArray,
+ TIpsPlgCriteriaOperation aOperator,
+ TBool aCaseSensitive )
+ {
+ FUNC_LOG;
+ TInt count( aKeywords.Count() );
+ if ( count != aKeywordSearchStatusArray.Count() )
+ {
+ User::Leave( KErrArgument );
+ }
+ // Compare the string will all the keywords
+ for ( TInt i=0; i<aKeywords.Count(); i++ )
+ {
+ if ( !aKeywordSearchStatusArray[i].iFound ) // keyword not yet found
+ {
+ TInt match;
+ if ( aCaseSensitive )
+ {
+ match = aToBeSearchedDes.Match( aKeywords[i] );
+ }
+ else
+ {
+ match = aToBeSearchedDes.MatchC( aKeywords[i] );
+ }
+
+ // KErrNotFound indicates that no match was found
+ if ( match != KErrNotFound )
+ {
+ aKeywordSearchStatusArray[i].iFound = ETrue;
+ // The 1st found keyword will be also the snippet
+ if ( iFirstMatchKeywordCharPos == KErrNotFound )
+ {
+ iFirstMatchKeywordCharPos = match;
+ }
+
+ if ( aOperator == EIpsPlgCriteriaOperationOR )
+ {
+ // As soon as one keyword is found, the OR search can stop
+ return ETrue;
+ }
+ }
+ }
+ }
+
+ // Check if there is still need to continue searching.
+ TBool keywordsFound;
+ switch ( aOperator )
+ {
+ case EIpsPlgCriteriaOperationAND:
+ keywordsFound = ETrue;
+ break;
+
+ case EIpsPlgCriteriaOperationOR:
+ keywordsFound = EFalse;
+ break;
+
+ default:
+ keywordsFound = ETrue; // to avoid warning
+ break;
+ }
+
+ // For AND search, all keywords must be found, thus if 1 is not found ->
+ // No hit
+ if( aOperator == EIpsPlgCriteriaOperationAND )
+ {
+ for ( TInt j(0); j < count; j++ )
+ {
+ if ( !aKeywordSearchStatusArray[j].iFound )
+ {
+ return EFalse;
+ }
+ }
+ }
+ return keywordsFound;
+ }
+
+// ----------------------------------------------------------------------------
+// CIpsPlgTextSearcher::CreateSnippetLC()
+// Creates the snippet from the 1st found keyword hit. 16 bit version.
+// ----------------------------------------------------------------------------
+//
+HBufC* CIpsPlgTextSearcher::CreateSnippetLC(
+ const TDesC& aToBeSearchedDes,
+ TInt& aSnippetCharPos,
+ TBool& aStartIncomplete,
+ TBool& aEndIncomplete ) const
+ {
+ FUNC_LOG;
+ TInt halfSnippetLen ( iSearchResultRecommendedSnippetLength / 2 );
+
+ TInt firstChar ( iFirstMatchKeywordCharPos - halfSnippetLen );
+ // if firstChar is negative, then we can give more space to lastChar
+ TInt lastChar (
+ iFirstMatchKeywordCharPos + halfSnippetLen - Min( firstChar, 0) );
+
+ TInt searchDesLastChar ( aToBeSearchedDes.Length() );
+
+ // if lastChar is go out of the total length, put the firstChar head toward
+ firstChar =
+ Max( 0, firstChar - Max( 0, ( lastChar - searchDesLastChar ) ) ) ;
+
+ aSnippetCharPos = halfSnippetLen + ( lastChar - searchDesLastChar );
+
+ aStartIncomplete = ETrue;
+ if ( firstChar <= 0 )
+ {
+ firstChar = 0;
+ aStartIncomplete = EFalse;
+ aSnippetCharPos = iFirstMatchKeywordCharPos;
+ }
+
+ aEndIncomplete = ETrue;
+ if ( lastChar >= searchDesLastChar )
+ {
+ lastChar = searchDesLastChar;
+ aEndIncomplete = EFalse;
+ }
+
+ return aToBeSearchedDes.Mid(
+ firstChar,
+ Min( lastChar - firstChar, searchDesLastChar - firstChar ) ).AllocLC();
+ }
+
+// ----------------------------------------------------------------------------
+// CIpsPlgTextSearcher::CreateSnippetLC()
+// Creates the snippet from the 1st found keyword hit. 8 bit version.
+// ----------------------------------------------------------------------------
+//
+HBufC* CIpsPlgTextSearcher::CreateSnippetLC(
+ const TDesC8& aToBeSearchedDes,
+ TInt& aSnippetCharPos,
+ TBool& aStartIncomplete,
+ TBool& aEndIncomplete )
+ {
+ FUNC_LOG;
+ TInt halfSnippetLen ( iSearchResultRecommendedSnippetLength / 2 );
+
+ TInt firstChar ( iFirstMatchKeywordCharPos - halfSnippetLen );
+ TInt lastChar (
+ iFirstMatchKeywordCharPos + halfSnippetLen - Min( firstChar, 0) );
+
+ TInt searchDesLastChar ( aToBeSearchedDes.Length() );
+
+ firstChar =
+ Max( 0, firstChar - Max( 0, ( lastChar - searchDesLastChar ) ) ) ;
+
+ aSnippetCharPos = halfSnippetLen + ( lastChar - searchDesLastChar );
+
+ aStartIncomplete = ETrue;
+ if ( firstChar <= 0 )
+ {
+ firstChar = 0;
+ aStartIncomplete = EFalse;
+ aSnippetCharPos = iFirstMatchKeywordCharPos;
+ }
+
+ aEndIncomplete = ETrue;
+ if ( lastChar >= searchDesLastChar )
+ {
+ lastChar = searchDesLastChar;
+ aEndIncomplete = EFalse;
+ }
+
+ HBufC8* snippet8 = aToBeSearchedDes.Mid( firstChar,
+ Min( lastChar - firstChar, searchDesLastChar - firstChar ) ).AllocLC();
+ HBufC* snippet= ConvertToUnicodeL( iRFs, *snippet8,
+ KCharacterSetIdentifierUtf8 );
+ CleanupStack::PopAndDestroy( snippet8 );
+ CleanupStack::PushL( snippet );
+ return snippet;
+ }
+
+// ----------------------------------------------------------------------------
+// CIpsPlgTextSearcher::ConvertFromUnicodeL()
+// Makes a conversion from unicode
+// ----------------------------------------------------------------------------
+HBufC8* CIpsPlgTextSearcher::ConvertFromUnicodeL(
+ RFs& aFs,
+ const TDesC16& aUnicodeSource,
+ TUint aTargetEncoding )
+ {
+ FUNC_LOG;
+ CCnvCharacterSetConverter* converter = CCnvCharacterSetConverter::NewLC();
+ if ( converter->PrepareToConvertToOrFromL(aTargetEncoding, aFs)
+ != CCnvCharacterSetConverter::EAvailable )
+ {
+ User::Leave( KErrNotSupported );
+ }
+
+ TBuf8<KUnicodeConversionBufferSize> temp8Buffer;
+ HBufC8* target = NULL;
+ TPtrC source16Ptr( aUnicodeSource );
+
+ for( ;; ) // conversion loop
+ {
+ TInt state = CCnvCharacterSetConverter::KStateDefault;
+ TInt returnValue =
+ converter->ConvertFromUnicode( temp8Buffer, source16Ptr, state );
+ if ( returnValue == CCnvCharacterSetConverter::EErrorIllFormedInput )
+ {
+ User::Leave( KErrCorrupt );
+ }
+ else
+ {
+ if ( returnValue < 0 ) // future-proof against "TError" expanding
+ {
+ User::Leave( KErrGeneral );
+ }
+ }
+
+ if ( !target )
+ {
+ target = temp8Buffer.AllocLC();
+ }
+ else
+ {
+ HBufC8* tmp =
+ target->ReAllocL( target->Length() + temp8Buffer.Length() );
+ CleanupStack::Pop( target );
+ target = tmp;
+ CleanupStack::PushL( target );
+ target->Des().Append( temp8Buffer );
+ }
+
+ if ( returnValue == 0 ) // All is converted without Errors
+ {
+ break;
+ }
+
+ // There is "returnValue" bytes not converted yet
+ source16Ptr.Set( source16Ptr.Right( returnValue ) );
+ }
+ CleanupStack::Pop( target ); // Ownership is transferred
+ CleanupStack::PopAndDestroy( converter );
+ return target;
+ }
+
+// ----------------------------------------------------------------------------
+// CIpsPlgTextSearcher::ConvertToUnicodeL()
+// Makes a conversion into unicode
+// ----------------------------------------------------------------------------
+HBufC16* CIpsPlgTextSearcher::ConvertToUnicodeL(
+ RFs& aFs,
+ const TDesC8& aSource,
+ TUint aSourceEncoding )
+ {
+ FUNC_LOG;
+ CCnvCharacterSetConverter* converter = CCnvCharacterSetConverter::NewLC();
+ if ( converter->PrepareToConvertToOrFromL( aSourceEncoding, aFs )
+ != CCnvCharacterSetConverter::EAvailable )
+ {
+ User::Leave( KErrNotSupported );
+ }
+
+ TBuf<KUnicodeConversionBufferSize> temp16Buffer;
+ HBufC* unicode = NULL;
+ TPtrC8 source8Ptr( aSource );
+
+ for( ;; ) // conversion loop
+ {
+ TInt state = CCnvCharacterSetConverter::KStateDefault;
+
+ TInt returnValue =
+ converter->ConvertToUnicode( temp16Buffer, source8Ptr, state );
+ if ( returnValue == CCnvCharacterSetConverter::EErrorIllFormedInput )
+ {
+ User::Leave( KErrCorrupt );
+ }
+ else
+ {
+ if ( returnValue < 0 ) // future-proof against "TError" expanding
+ {
+ User::Leave( KErrGeneral );
+ }
+ }
+
+ if ( !unicode )
+ {
+ unicode = temp16Buffer.AllocLC();
+ }
+ else
+ {
+ HBufC* tmp =
+ unicode->ReAllocL( unicode->Length() + temp16Buffer.Length() );
+ CleanupStack::Pop( unicode );
+ unicode = tmp;
+ CleanupStack::PushL( unicode );
+ unicode->Des().Append( temp16Buffer );
+ }
+
+ if ( returnValue == 0 ) // All is converted without Errors
+ {
+ break;
+ }
+
+ // There is "returnValue" bytes not converted yet
+ source8Ptr.Set( source8Ptr.Right( returnValue ) );
+ }
+
+ CleanupStack::Pop( unicode ); // Ownership is transferred
+ CleanupStack::PopAndDestroy( converter );
+ return unicode;
+ }
+
+
+
+
+
+