sl@0: // Copyright (c) 1998-2009 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 "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: // SQL Like predicate node sl@0: // sl@0: // sl@0: sl@0: #include "UQ_STD.H" sl@0: sl@0: inline TUint8* TextCopy(TUint8* aDest,const TUint8* aSrc,TInt aLen) sl@0: {return Mem::Copy(aDest,aSrc,aLen);} sl@0: inline TUint16* TextCopy(TUint16* aDest,const TUint16* aSrc,TInt aLen) sl@0: {return (TUint16*)Mem::Copy(aDest,aSrc,aLen<<1);} sl@0: sl@0: // template Class HMatcherPattern sl@0: sl@0: template sl@0: inline HMatcherPattern* HMatcherPattern::Realloc(HMatcherPattern* aThis,TInt aSize) sl@0: {return STATIC_CAST(TThis*,User::ReAlloc(aThis,_FOFF(TThis,iPattern[aSize])));} sl@0: sl@0: /** sl@0: Creates a HMatcherPattern that converts the pattern into more manageable pieces sl@0: based on a delimeter that is the wildcard * (asterisk). sl@0: sl@0: Characters between * (asterisks) must not number greater than KMaxSegmentLength. sl@0: If only one * exists then the length is taken from the start and end of pattern. sl@0: If these segments contain ? (question mark) wildcard than they must not number sl@0: greater than KMaxSegmentLength-2. sl@0: sl@0: The user is responsible for the returned pointer's memory. sl@0: sl@0: @param aPattern The search pattern to match. sl@0: @param aEscape ESCAPE clause sl@0: @leave KErrNoMemory if no more memory is available. sl@0: @leave KErrArgument if the search pattern segment length is greater sl@0: than KMaxSegmentLength, sl@0: @return The newly constructed pattern pointer. sl@0: @see KMaxSegmentLength sl@0: */ sl@0: template sl@0: HMatcherPattern* HMatcherPattern::NewL(const D& aPattern, TBool aEscape) sl@0: { sl@0: TThis* self=0; sl@0: TInt r=Construct(self,aPattern,aEscape); sl@0: if (r!=KErrNone) sl@0: { sl@0: User::Free(self); sl@0: __LEAVE(r); sl@0: } sl@0: return self; sl@0: } sl@0: sl@0: template sl@0: TInt HMatcherPattern::MatchL(const D& aDes,const TTextOps& aTextOp) const sl@0: // sl@0: // Test the pattern against the supplied descriptor sl@0: // sl@0: { sl@0: TDesMatcher matcher(aDes); sl@0: return matcher.MatchL(*this,aTextOp); sl@0: } sl@0: sl@0: template sl@0: TInt HMatcherPattern::MatchL(MStreamBuf& aBuf,TInt aLength,const TTextOps& aTextOp) const sl@0: // sl@0: // Test the pattern against the supplied stream sl@0: // sl@0: { sl@0: TStreamMatcher matcher(aBuf,aLength); sl@0: return matcher.MatchL(*this,aTextOp); sl@0: } sl@0: sl@0: /** sl@0: Breaks up a given search pattern into manageable segments. sl@0: sl@0: The pattern is broken into segments. These segments are organised sl@0: from the segment delimeter that is the wildcard * (asterisk). sl@0: So in effect a segment may contain other wildcards (i.e. ?) or sl@0: the entire pattern (no embedded asterisks) as these at least MUST match. sl@0: sl@0: The cell is created and updated with the segments type and length, and also sl@0: the segment itself. sl@0: sl@0: Not including asterisks, the segment must be no longer than length KMaxSegmentLength. sl@0: However, if the segment has a ? (question mark) wildcard within it then the sl@0: segment must be no longer than length KMaxSegmentLength-2. sl@0: sl@0: This is due to the way the Find and Match functions of TDes work. Match understands sl@0: wildcards whilst Find does not. sl@0: sl@0: The match algorithm depends on KMaxSegmentLength being smaller than the sl@0: text read buffer, and for efficiency should not be more than half the size sl@0: of the read buffer. Also KMaxSegmentLength must currently fit into 8 bits, sl@0: as it is embedded into a single character in an 8-bit text matching buffer. sl@0: [So increasing KMaxSegmentLength is not a simple exercise.] sl@0: sl@0: The search is repeated for each segment within the pattern. Increasing the cell sl@0: size and inserting each segment and associated segment data. sl@0: sl@0: On reaching the end of the pattern this data is passed back to the user. sl@0: The user is responsible for this returned pointers memory. sl@0: sl@0: @param aCell On return points to a cell matching this pattern. sl@0: @param aPattern The search pattern to match. sl@0: @param aEscape ESCAPE clause sl@0: @return KErrNoMemory if no memory is available to create or sl@0: increase the size of a cell, sl@0: KErrArgument if the search pattern segment length is greater sl@0: than KMaxSegmentLength, sl@0: KErrNone if the match was successful. sl@0: @see KMaxSegmentLength sl@0: */ sl@0: template sl@0: TInt HMatcherPattern::Construct(HMatcherPattern*& aCell,const D& aPattern,TBool aEscape) sl@0: { sl@0: const T* pM=aPattern.Ptr(); sl@0: const T* const eM=pM+aPattern.Length(); sl@0: TInt size=(eM-pM)+KPatternGranularity; sl@0: TThis* self=Realloc(0,size); sl@0: if (!self) sl@0: return KErrNoMemory; sl@0: aCell=self; sl@0: T* seg=&self->iPattern[0]; sl@0: const T* end=&self->iPattern[size]; sl@0: TInt term; // terminating code sl@0: sl@0: if (eM==pM) sl@0: term=ENull; sl@0: else sl@0: { sl@0: term=EStop; sl@0: do sl@0: { sl@0: //Following code is for the implementation of limited-ESCAPE-clause sl@0: if(aEscape) sl@0: { sl@0: const T* here=pM; sl@0: TInt len = aPattern.Length(); sl@0: if (len>KMaxSegmentLength) sl@0: return KErrArgument; sl@0: *seg++=T(EEscape ); sl@0: *seg++=T(len); sl@0: seg=TextCopy(seg,here,len); sl@0: break; sl@0: } sl@0: T m=*pM; sl@0: if (m==KMatchAny) sl@0: { sl@0: term=ESuccess; sl@0: do sl@0: { sl@0: if (++pM==eM) sl@0: break; sl@0: m=*pM; sl@0: } while (m==KMatchAny); sl@0: if (pM==eM) sl@0: break; sl@0: } sl@0: const T* here=pM; sl@0: TInt type; sl@0: if (m==KMatchOne) sl@0: { sl@0: while (++pMKMaxSegmentLength) sl@0: return KErrArgument; sl@0: *seg++=T(len); sl@0: if (type==ESkip) sl@0: len=0; sl@0: if (seg+4+len>end) sl@0: { sl@0: TInt newsize=end-&self->iPattern[0]+KPatternGranularity; sl@0: self=Realloc(self,newsize); sl@0: if (!self) sl@0: return KErrNoMemory; sl@0: seg+=&self->iPattern[0]-&aCell->iPattern[0]; sl@0: end=&self->iPattern[newsize]; sl@0: aCell=self; sl@0: } sl@0: if (type==(EMiddle|EWild)) sl@0: { sl@0: *seg++=T(KMatchAny); sl@0: ++here; sl@0: --len; sl@0: } sl@0: seg=TextCopy(seg,here,len); sl@0: } while (pMiPattern[0]); sl@0: return KErrNone; sl@0: } sl@0: sl@0: // class TMatcher sl@0: sl@0: template sl@0: TBool TMatcher::MatchL(const HMatcherPattern& aPattern,const TTextOps& aTextOp) sl@0: { sl@0: const T* pM=&aPattern.iPattern[0]; sl@0: const T* eB; sl@0: const T* pB=UnderflowL(eB); sl@0: for (;;) sl@0: { sl@0: TInt segment=*pM; sl@0: switch (segment&EMask) sl@0: { sl@0: case ENull: sl@0: return pB==eB; sl@0: case ESuccess: sl@0: return ETrue; sl@0: case EStop: sl@0: if (pB==eB) sl@0: pB=UnderflowL(eB); sl@0: return pB==eB; sl@0: case ESkip: sl@0: { sl@0: TInt len=*++pM; sl@0: TInt skip=len+pB-eB; sl@0: if (skip>0) sl@0: { sl@0: pB=UnderflowL(eB)+skip; sl@0: if (pB>eB) sl@0: return EFalse; sl@0: } sl@0: else sl@0: pB+=len; sl@0: ++pM; sl@0: } sl@0: break; sl@0: //Following code is for the implementation of limited-ESCAPE-clause sl@0: case EEscape: sl@0: { sl@0: TInt len=*++pM; sl@0: ++pM; sl@0: TInt bLen=eB-pB; sl@0: if (bLen=0) sl@0: { // found it sl@0: pB+=pos+match; sl@0: break; sl@0: } sl@0: // not found, next chunk of data please. sl@0: pB=UnderflowL(eB,match-1); sl@0: } sl@0: pM+=len; sl@0: } sl@0: break; sl@0: case EEnd: // match the last segment sl@0: { sl@0: TInt len=*++pM; sl@0: ++pM; sl@0: TInt left=eB-pB; sl@0: if (leftlen) sl@0: pB=UnderflowL(eB,len); sl@0: if (segment&EWild) sl@0: { sl@0: if (aTextOp.Match(pB,len,pM,len)<0) sl@0: return EFalse; sl@0: } sl@0: else sl@0: { sl@0: if (aTextOp.Compare(pB,len,pM,len)!=0) sl@0: return EFalse; sl@0: } sl@0: } sl@0: return ETrue; sl@0: } sl@0: } sl@0: } sl@0: sl@0: // Class TDesMatcher sl@0: sl@0: template sl@0: inline TDesMatcher::TDesMatcher(const D& aDes) sl@0: {iEnd=(iPtr=aDes.Ptr())+aDes.Length();} sl@0: sl@0: template sl@0: const T* TDesMatcher::UnderflowL(const T*& aEnd,TInt aRetain) sl@0: { sl@0: const T* ptr=iPtr-aRetain; sl@0: aEnd=iPtr=iEnd; sl@0: return ptr; sl@0: } sl@0: sl@0: // Class TStreamMatcher sl@0: sl@0: template sl@0: inline TStreamMatcher::TStreamMatcher(MStreamBuf& aStreamBuf,TInt aLength) sl@0: :iStream(&aStreamBuf),iRemain(aLength),iEnd(&iBuffer[EBufSize]) sl@0: {} sl@0: sl@0: template sl@0: const T* TStreamMatcher::UnderflowL(const T*& aEnd,TInt aRetain) sl@0: { sl@0: if (iRemain==0) sl@0: { // no more stream data, don't move etc. sl@0: aEnd=iEnd; sl@0: return iEnd-aRetain; sl@0: } sl@0: else sl@0: { sl@0: T* rp=&iBuffer[0]; sl@0: if (aRetain) sl@0: rp=TextCopy(rp,iEnd-aRetain,aRetain); sl@0: TInt read=Min(EBufSize-aRetain,iRemain); sl@0: iStream.ReadL(rp,read); sl@0: iRemain-=read; sl@0: aEnd=iEnd=rp+read; sl@0: return iBuffer; sl@0: } sl@0: } sl@0: sl@0: // Class RSqlLiteral sl@0: sl@0: void RSqlLiteral::ToPattern8L(TBool aEscape) sl@0: // sl@0: // Convert a Buf8 to an 8-bit pattern sl@0: // sl@0: { sl@0: __ASSERT(iType==EBuf8); sl@0: HMatcherPattern8* pattern=HMatcherPattern8::NewL(Text8(),aEscape); sl@0: User::Free(iVal.iAlloc); sl@0: iVal.iAlloc=pattern; sl@0: iType=EPattern8; sl@0: } sl@0: sl@0: void RSqlLiteral::ToPattern16L(TBool aEscape) sl@0: // sl@0: // Convert a Buf8 to an 8-bit pattern sl@0: // sl@0: { sl@0: __ASSERT(iType==EBuf16); sl@0: HMatcherPattern16* pattern=HMatcherPattern16::NewL(Text16(),aEscape); sl@0: User::Free(iVal.iAlloc); sl@0: iVal.iAlloc=pattern; sl@0: iType=EPattern16; sl@0: } sl@0: sl@0: sl@0: // Class CSqlLikePredicate sl@0: sl@0: LOCAL_C TInt MatchLength(const TText* aPtr,const TText* aEnd) sl@0: { sl@0: TInt match=0; sl@0: while (aPtr>1,aTextOp); sl@0: CleanupStack::PopAndDestroy(); sl@0: } sl@0: } sl@0: else if (column.Size()=0; sl@0: } sl@0: return NodeType()==ELike ? match : !match; sl@0: }