userlibandfileserver/fileserver/sfat/sl_utl.cpp
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:26:05 +0100
branchRCL_3
changeset 29 743008598095
parent 2 4122176ea935
permissions -rw-r--r--
Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h) Have multiple extension sections in the bld.inf, one for each version of the compiler. The RVCT version building the tools will build the runtime libraries for its version, but make sure we extract all the other versions from zip archives. Also add the archive for RVCT4.

// Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "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:
//

//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!
//!! WARNING!! DO NOT edit this file !! '\sfat' component is obsolete and is not being used. '\sfat32'replaces it
//!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!


#include "sl_std.h"

//-----------------------------------------------------------------------------
/**
    Removes trailing dots from aName.
    @return new string descriptor that may have its length adjusted
*/
TPtrC RemoveTrailingDots(const TDesC& aName)
{
    TInt len = aName.Length();
    
    while(len > 0)
    {
        if(aName[len-1] == '.')
            len--;
        else
            break;
    }

    TPtrC ptrNoDots(aName.Ptr(), len);
    return ptrNoDots;
}


TUint32 Log2(TUint32 aVal)
{
    __ASSERT_COMPILE(sizeof(TUint32) == 4);
    ASSERT(aVal);

    TUint32 bitPos=31;

    if(!(aVal >> 16)) {bitPos-=16; aVal<<=16;}
    if(!(aVal >> 24)) {bitPos-=8;  aVal<<=8 ;}
    if(!(aVal >> 28)) {bitPos-=4;  aVal<<=4 ;}
    if(!(aVal >> 30)) {bitPos-=2;  aVal<<=2 ;}
    if(!(aVal >> 31)) {bitPos-=1;}
    
    return bitPos;
}


TTime DosTimeToTTime(TInt aDosTime,TInt aDosDate)
//
//  Deciphers the dos time/date entry information and converts to TTime
//
    {
    TInt secMask=0x1F;
    TInt minMask=0x07E0;
    TInt hrMask=0xF800;
    TInt dayMask=0x1F;
    TInt monthMask=0x01E0;
    TInt yearMask=0xFE00;

    TInt secs=(aDosTime&secMask)*2;
    TInt mins=(aDosTime&minMask)>>5;
    TInt hrs=(aDosTime&hrMask)>>11;
    TInt days=(aDosDate&dayMask)-1;
    TMonth months=(TMonth)(((aDosDate&monthMask)>>5)-1);
    TInt years=((aDosDate&yearMask)>>9)+1980;
    
    TDateTime datetime;
    TInt ret=datetime.Set(years,months,days,hrs,mins,secs,0);
    if (ret==KErrNone)
        return(TTime(datetime));
    return(TTime(0));
    }

TInt DosTimeFromTTime(const TTime& aTime)
//
// Converts a TTime to a dos time
//
    {
    TDateTime dateTime=aTime.DateTime();
    TInt dosSecs=dateTime.Second()/2;
    TInt dosMins=dateTime.Minute()<<5;
    TInt dosHrs=dateTime.Hour()<<11;
    return dosSecs|dosMins|dosHrs;
    }

TInt DosDateFromTTime(const TTime& aTime)
//
// Converts a TTime to a dos date
//
    {

    TDateTime dateTime=aTime.DateTime();
    TInt dosDays=dateTime.Day()+1;
    TInt dosMonths=(dateTime.Month()+1)<<5;
    TInt dosYears=(dateTime.Year()-1980)<<9;
    return dosDays|dosMonths|dosYears;
    }

TBuf8<12> DosNameToStdFormat(const TDesC8& aDosName)
//
// Converts xxx.yyy to standard format aaaaaaaayyy
//
    {

    __ASSERT_DEBUG(aDosName.Length()>=0 && aDosName.Length()<=12,Fault(EFatBadDosFormatName));
    TBuf8<12> result;
    Mem::Fill((TUint8*)result.Ptr(),result.MaxSize(),' ');
    TInt dotPos=aDosName.Locate('.');
    if (dotPos==KErrNotFound)
        {
        result=aDosName;
        result.SetLength(11);
        return result;
        }
    result=aDosName.Left(dotPos);
    result.SetLength(11);
    TPtr8 ext(&result[8],3);
    ext=aDosName.Right(aDosName.Length()-dotPos-1);
    return result;
    }

TBuf8<12> DosNameFromStdFormat(const TDesC8& aStdFormatName)
//
// Converts aaaaaaaayyy to dos name format xxx.yyy
//
    {

    __ASSERT_DEBUG(aStdFormatName.Length()==11,Fault(EFatBadStdFormatName));
    TBuf8<12> result;
    TInt nameLen=aStdFormatName.Locate(' ');
    if (nameLen>8 || nameLen==KErrNotFound)
        nameLen=8;
    result=aStdFormatName.Left(nameLen);
    TPtrC8 ext(&aStdFormatName[8],3);
    TInt extLen=ext.Locate(' ');
    if (extLen)
        result.Append(TChar('.'));
    if (extLen==KErrNotFound)
        extLen=3;
    result.Append(ext.Left(extLen));
    if(result.Length() && result[0]==0x05 )
        {
        result[0]=0xE5;
        }
    return result;
    }

TInt NumberOfVFatEntries(TInt aNameLength)
//
// Return the number of VFat entries required to describe a filename of length aNameLength
//
    {
    TInt numberOfEntries=0;
    if (aNameLength%KMaxVFatEntryName)
        aNameLength++;  //  Include a zero terminator
//  If aNameLength is a exact multiple of KMaxVFatEntryName, don't bother
//  with a zero terminator - it just adds an unnecessary directory entry        
    
    numberOfEntries=(1+(aNameLength/KMaxVFatEntryName));    
    
    if (aNameLength%KMaxVFatEntryName)
        numberOfEntries++;
    
    return(numberOfEntries);
    }

//-----------------------------------------------------------------------------
/** 
    Calculate DOS short name checksum
    @param aShortName short name descriptor (must be at least 11 bytes long)
    @return checksum
*/
TUint8 CalculateShortNameCheckSum(const TDesC8& aShortName)
    {

    ASSERT(aShortName.Length() >= KFatDirNameSize);
    const TUint8* pName = aShortName.Ptr();

    const TUint32 w0 = ((const TUint32*)pName)[0];
    const TUint32 w1 = ((const TUint32*)pName)[1];

    TUint32 chkSum = w0 & 0xFF;
    
    chkSum = (TUint8)(((chkSum<<7) | (chkSum>>1)) + ((w0 << 16) >> 24));
    chkSum = (TUint8)(((chkSum<<7) | (chkSum>>1)) + ((w0 << 8)  >> 24));
    chkSum = (TUint8)(((chkSum<<7) | (chkSum>>1)) + ( w0 >> 24));

    chkSum = (TUint8)(((chkSum<<7) | (chkSum>>1)) + (w1) & 0xFF);
    chkSum = (TUint8)(((chkSum<<7) | (chkSum>>1)) + ((w1 << 16) >> 24));
    chkSum = (TUint8)(((chkSum<<7) | (chkSum>>1)) + ((w1 << 8)  >> 24));
    chkSum = (TUint8)(((chkSum<<7) | (chkSum>>1)) + ( w1 >> 24));

    chkSum = (TUint8)(((chkSum<<7) | (chkSum>>1)) + pName[8]);
    chkSum = (TUint8)(((chkSum<<7) | (chkSum>>1)) + pName[9]);
    chkSum = (TUint8)(((chkSum<<7) | (chkSum>>1)) + pName[10]);

    return (TUint8)chkSum;
    }

//-----------------------------------------------------------------------------

const TUint32 K_FFFF = 0xFFFFFFFF; //-- all one bits, beware rigth shifts of signed integers!


RBitVector::RBitVector()
          :iNumBits(0), ipData(NULL), iNumWords(0)
    {
    }


RBitVector::~RBitVector()
    {
    Close();
    }

/**
    Panics.
    @param aPanicCode   a panic code
*/
void RBitVector::Panic(TPanicCode aPanicCode) const
    {
    _LIT(KPanicCat,"RBitVector");
    User::Panic(KPanicCat, aPanicCode);
    }

/** explicitly closes the object and deallocates memory */
void RBitVector::Close()
    {
    iNumBits = 0;
    iNumWords =0;
    User::Free(ipData);
    ipData = NULL;
    }

//-----------------------------------------------------------------------------

/**
    Comparison perator.
    @param  aRhs a vector to compate with.
    @panic ESizeMismatch in the case of different vector sizes
*/
TBool RBitVector::operator==(const RBitVector& aRhs) const
    {
    __ASSERT_ALWAYS(ipData, Panic(ENotInitialised));
    __ASSERT_ALWAYS(iNumBits == aRhs.iNumBits, Panic(ESizeMismatch));


    if(!iNumBits)
        return ETrue; //-- comparing 0-lenght arrays

    if(this == &aRhs)
        return ETrue; //-- comparing with itself

    if(iNumWords >= 1)
        {
        const TUint32 cntBytes = (iNumBits >> 5) << 2; //-- bytes to compare
        if(memcompare((const TUint8*)ipData, cntBytes, (const TUint8*)aRhs.ipData, cntBytes))
            return EFalse;
        }

    const TUint32 bitsRest  = iNumBits & 0x1F;
    if(bitsRest)
        {
        const TUint32 mask = K_FFFF >> (32-bitsRest);
        return ( (ipData[iNumWords-1] & mask) == (aRhs.ipData[iNumWords-1] & mask) );
        }
    
    return ETrue;
    }

TBool RBitVector::operator!=(const RBitVector& aRhs) const  
    {
    return ! ((*this) == aRhs);
    } 

//-----------------------------------------------------------------------------

/** The same as Create(), but leaves on error */
void RBitVector::CreateL(TUint32 aNumBits)
    {
    User::LeaveIfError(Create(aNumBits));
    }


/**
    Create the vector with the size of aNumBits bits.
    @return system-wide error codes:
        KErrNoMemory    unable to allocate sufficient amount of memory for the array
        KErrInUse       an attempt to call Create() for non-empty vector. Close it first.
        KErrArgument    invalid aNumBits value == 0
*/
TInt RBitVector::Create(TUint32 aNumBits)
    {

    if(ipData)
        return KErrInUse; //-- array is already in use. Close it first.

    if(!aNumBits)
        return KErrArgument;

    //-- memory is allocated by word (32 bit) quiantities
    const TUint32 numWords = (aNumBits >> 5) + ((aNumBits & 0x1F) > 0 ? 1:0);
    ipData = (TUint32*)User::AllocZ(numWords << 2);

    if(!ipData)
        return KErrNoMemory;

    iNumBits  = aNumBits;
    iNumWords = numWords;

    return KErrNone;
    }


/**
    Fill a bit vector with a given bit value
    @param aVal a bit value
*/
void RBitVector::Fill(TBool aVal)
    {
    __ASSERT_ALWAYS(ipData, Panic(ENotInitialised));
    memset(ipData, (aVal ? 0xFF : 0x00), iNumWords << 2);
    }

/** Invert all bits in a bit vector */
void RBitVector::Invert()
{
    __ASSERT_ALWAYS(ipData, Panic(ENotInitialised));
    for(TUint32 i=0; i<iNumWords; ++i)
        ipData[i] ^= K_FFFF;
}


/**
    Perform "And" operation between 2 vectors. They shall be the same size.
    @param  aRhs a vector from the right hand side
    @panic ESizeMismatch in the case of different vector sizes
*/
void RBitVector::And(const RBitVector& aRhs)
    {
    __ASSERT_ALWAYS(ipData, Panic(ENotInitialised));
    __ASSERT_ALWAYS(iNumBits == aRhs.iNumBits, Panic(ESizeMismatch));
    for(TUint32 i=0; i<iNumWords; ++i)
        {
        ipData[i] &= aRhs.ipData[i];
        }
    }

/**
    Perform "Or" operation between 2 vectors. They shall be the same size.    
    @param  aRhs a vector from the right hand side
    @panic ESizeMismatch in the case of different vector sizes
*/
void RBitVector::Or(const RBitVector& aRhs)
    {
    __ASSERT_ALWAYS(ipData, Panic(ENotInitialised));
    __ASSERT_ALWAYS(iNumBits == aRhs.iNumBits, Panic(ESizeMismatch));
    for(TUint32 i=0; i<iNumWords; ++i)
        {
        ipData[i] |= aRhs.ipData[i];
        }
    }

/**
    Perform "Xor" operation between 2 vectors. They shall be the same size.    
    @param  aRhs a vector from the right hand side
    @panic ESizeMismatch in the case of different vector sizes
*/
void RBitVector::Xor(const RBitVector& aRhs)
    {
    __ASSERT_ALWAYS(ipData, Panic(ENotInitialised));
    __ASSERT_ALWAYS(iNumBits == aRhs.iNumBits, Panic(ESizeMismatch));
    for(TUint32 i=0; i<iNumWords; ++i)
        {
        ipData[i] ^= aRhs.ipData[i];
        }
    }

//-----------------------------------------------------------------------------
/**
    Fill a range from bit number "aIndexFrom" to "aIndexTo" inclusively with the value of aVal
    
    @param  aIndexFrom  start bit number (inclusive)
    @param  aIndexTo    end bit number (inclusive)
    @param  aVal        the value to be used to fill the range (0s or 1s)
*/
void RBitVector::Fill(TUint32 aIndexFrom, TUint32 aIndexTo, TBool aVal)
    {
    __ASSERT_ALWAYS(ipData, Panic(ENotInitialised));

    //-- swap indexes if they are not in order
    if(aIndexFrom > aIndexTo)
        {
        const TUint32 tmp = aIndexFrom;
        aIndexFrom = aIndexTo;
        aIndexTo = tmp;
        }

    __ASSERT_ALWAYS((aIndexFrom < iNumBits) && (aIndexTo < iNumBits), Panic(EIndexOutOfRange));

    const TUint32 wordStart = WordNum(aIndexFrom);
    const TUint32 wordTo    = WordNum(aIndexTo);

    if(aVal)
        {//-- filling a range with '1'
        
        TUint32 shift = BitInWord(aIndexFrom);
        const TUint32 mask1 = (K_FFFF >> shift) << shift;

        TUint32 mask2 = K_FFFF;
        shift = 1+BitInWord(aIndexTo);
        if(shift < 32)
            {
            mask2 = ~((mask2 >> shift) << shift);
            }

        if(wordTo == wordStart)
            {//-- a special case, filling is in the same word
            ipData[wordStart] |= (mask1 & mask2);
            }
        else
            {
            ipData[wordStart] |= mask1; 
            ipData[wordTo]    |= mask2;
            
            const TUint32 wholeWordsBetween = wordTo - wordStart - 1; //-- whole words that can be bulk filled

            if(wholeWordsBetween)
                memset(ipData+wordStart+1, 0xFF, wholeWordsBetween << 2);
                            
            }
        }
    else
        {//-- filling a range with '0'
        
        //-- if you need this functionality, remove the panic and uncomment the code below.

        Panic(ENotImplemented);
        
        /*
        TUint32 shift = BitInWord(aIndexFrom);
        const TUint32 mask1 = ~((K_FFFF >> shift) << shift);

        TUint32 mask2 = 0;
        shift = 1+BitInWord(aIndexTo);
        if(shift < 32)
            {
            mask2 = ((K_FFFF >> shift) << shift);
            }

        if(wordTo == wordStart)
            {//-- a special case, filling is in the same word
            ipData[wordStart] &= (mask1 | mask2);
            }
        else
            {
            ipData[wordStart] &= mask1; 
            ipData[wordTo]    &= mask2;
            
            const TUint32 wholeWordsBetween = wordTo - wordStart - 1; //-- whole words that can be bulk filled

            if(wholeWordsBetween)
                memset(ipData+wordStart+1, 0x00, wholeWordsBetween << 2);
                            
            }
        */
        }

    }

//-----------------------------------------------------------------------------

/**
    Search for a specified bit value ('0' or '1') in the vector from the given position.
    @param  aStartPos   zero-based index; from this position the search will start. This position isn't included to the search.
                        On return may contain a new position if the specified bit is found in specified direction.
    @param  aBitVal     zero or non-zero bit to search.
    @param  aDir        Specifies the search direction

    @return ETrue if the specified bit value is found; aStartPos gets updated.
            EFalse otherwise.

*/
TBool RBitVector::Find(TUint32& aStartPos, TBool aBitVal, TFindDirection aDir) const
    {
    __ASSERT_ALWAYS(aStartPos < iNumBits, Panic(EIndexOutOfRange));
    ASSERT(iNumWords && ipData);

    switch(aDir)
        {
        case ERight:    //-- Search from the given position to the right
            return FindToRight(aStartPos, aBitVal);

        case ELeft:     //-- Search from the given position to the left (towards lower index)
            return FindToLeft(aStartPos, aBitVal);

        case ENearestL: //-- Search for the nearest value in both directions starting from left
            return FindNearest(aStartPos, aBitVal, ETrue);

        case ENearestR: //-- Search for the nearest value in both directions starting from right
            return FindNearest(aStartPos, aBitVal, EFalse);

        default:
            Panic(EWrondFindDirection);
            return EFalse;

        };
    
    }

//-----------------------------------------------------------------------------
/**
    Internal method to look for a given bit value in the right direction.
    see TBool RBitVector::Find(...)
*/
TBool RBitVector::FindToRight(TUint32& aStartPos, TBool aBitVal) const
    {
    if(aStartPos >= iNumBits-1)
        return EFalse; //-- no way to the right

    const TUint32 startPos = aStartPos+1;
    const TUint32 fInvert = aBitVal ? 0 : K_FFFF; //-- invert everything if we are looking for '0' bit

    TUint32 wordNum = WordNum(startPos);
    TUint32 val = ipData[wordNum] ^ fInvert;

    if(wordNum == iNumWords-1)
        {//-- process the last word in the array, some higher bits might not belong to the bit vector
        val = MaskLastWord(val);
        }

    const TUint32 shift = BitInWord(startPos);
    val = (val >> shift) << shift; //-- mask unused low bits

    if(val)
        {//-- there are '1' bits in the current word
        goto found;
        }
    else
        {//-- search in higher words
        wordNum++;

        while(iNumWords-wordNum > 1)
            {
            val = ipData[wordNum] ^ fInvert;
            if(val)
                goto found;

            wordNum++;
            }

        if(wordNum == iNumWords-1)
            {//-- process the last word in the array, some higher bith might not belong to the bit vector
            val = ipData[wordNum] ^ fInvert;
            val = MaskLastWord(val);

            if(val)
                goto found;
            }
        }

    return EFalse; //-- haven't found anything

  found:

    val &= (~val+1); //-- select rightmost bit
    aStartPos = (wordNum << 5)+Log2(val);
    return ETrue;
    }


//-----------------------------------------------------------------------------

/**
    Internal method to look for a given bit value in the left direction.
    see TBool RBitVector::Find(...)
*/
TBool RBitVector::FindToLeft(TUint32& aStartPos, TBool aBitVal) const
{
    if(!aStartPos)
        return EFalse; //-- no way to the left
    
    const TUint32 startPos=aStartPos-1;
    const TUint32 fInvert = aBitVal ? 0 : K_FFFF; //-- invert everything if we are looking for '0' bit

    TUint32 wordNum = WordNum(startPos);
    TUint32 val = ipData[wordNum] ^ fInvert;

    const TUint32 shift = 31-(BitInWord(startPos));
    val = (val << shift) >> shift; //-- mask unused high bits

    if(val)
    {//-- there are '1' bits in the current word
        goto found;
    }
    else
    {//-- search in the lower words
        while(wordNum)
        {
            wordNum--;
            val=ipData[wordNum] ^ fInvert;
            if(val)
                goto found;
        }
    }

    return EFalse; //-- nothing found

 found:
    aStartPos = (wordNum << 5)+Log2(val);
    return ETrue;
}

//-----------------------------------------------------------------------------

/**
    Internal method to look for a given bit value in the both directions.
    see TBool RBitVector::Find(...)
*/
TBool RBitVector::FindNearest(TUint32& aStartPos, TBool aBitVal, TBool aToLeft) const
{
    if(iNumBits < 2)
        return EFalse;

    if(aStartPos == 0)
        return FindToRight(aStartPos, aBitVal);

    if(aStartPos == iNumBits-1)
        return FindToLeft(aStartPos, aBitVal);

    
    const TUint32 fInvert = aBitVal ? 0 : K_FFFF; //-- invert everything if we are looking for '0' bit
    
    TUint32 wordNum = WordNum(aStartPos);
    TUint32 l_Idx; //-- index of the word to the left
    TUint32 r_Idx; //-- index of the word to the right
    
    l_Idx = r_Idx = wordNum;

    TBool   noWayLeft  = (wordNum == 0);            //-- if we are in the first word
    TBool   noWayRight = (wordNum == iNumWords-1);  //-- if we are in the last word

    //-- look in the current word first
    TUint32 val = ipData[wordNum] ^ fInvert;
    
    if(noWayRight)
    {   //-- this is the last word in the array, mask unused high bits in the last word
        val = MaskLastWord(val);
    }

    const TUint32 bitPos = aStartPos & 0x1F;
    val &= ~(1<<bitPos); //-- mask the bit at current position
    
    if(val == 0)
    {//-- no '1' bits in the current word
        noWayLeft  = ItrLeft(l_Idx);
        noWayRight = ItrRight(r_Idx);
    }
    else if(bitPos == 0)
    {
        noWayLeft = ItrLeft(l_Idx); //-- move to the previous word
    }
    else if(bitPos == 31)
    {
        noWayRight = ItrRight(r_Idx); //-- move to the next word
    }
    else
    {//-- look in the current word, in both halves to the left and right from the start position
        
        const TUint32 shift1 = 32-bitPos;
        const TUint32 partLo = (val << shift1) >> shift1; //-- towards lower bits

        const TUint32 shift2 = bitPos+1;
        const TUint32 partHi = (val >> shift2) << shift2; //-- towards higher bits 
        

        if(partLo && !partHi) //-- only lower part has '1' bits   
        {
            aStartPos = (wordNum << 5)+Log2(partLo);
            return ETrue;
        }
        else if(!partLo && partHi) //-- only higher part has '1' bits
        {
            aStartPos = (wordNum << 5)+Log2( (partHi & (~partHi+1)) );
            return ETrue;
        }
        else if(partLo && partHi) //-- both parts contain '1' bits, select the nearest one
        {
            const TUint32 posL = (wordNum << 5)+Log2(partLo);
            const TUint32 posR = (wordNum << 5)+Log2( (partHi & (~partHi+1)) );
        
            ASSERT(aStartPos > posL);
            ASSERT(posR > aStartPos);
            const TUint32 distL = aStartPos-posL;
            const TUint32 distR = posR-aStartPos;

            if(distL < distR)
            {
                aStartPos = posL;
                return ETrue;
            }
            else if(distL > distR)
            {
                aStartPos = posR;
                return ETrue;
            }
            else
            {//-- distL == distR, take into account search priority
                aStartPos = aToLeft ? posL : posR;
                return ETrue;
            }
        }
        else //-- (!partLo && !partHi), nothing in the current word
        {
            ASSERT(0);
        }

    }// if(bitPos > 0 && bitPos < 31)

    //-- now we are processing separate words from both sides of the search position
    for(;;)
    { 
        TUint32 wL = ipData[l_Idx] ^ fInvert;
        TUint32 wR = ipData[r_Idx] ^ fInvert;
        if(r_Idx == iNumWords-1)
        {   //-- this is the last word in the array, mask unused high bits in the last word
            wR = MaskLastWord(wR);
        }

        if(wL && !wR)
        {
            aStartPos = (l_Idx << 5)+Log2(wL);
            return ETrue;
        }
        else if(!wL && wR)
        {
            aStartPos = (r_Idx << 5)+Log2( (wR & (~wR+1)) );
            return ETrue;
        }
        else if(wL && wR)
        {
            const TUint32 posL = (l_Idx << 5)+Log2(wL);
            const TUint32 posR = (r_Idx << 5)+Log2( (wR & (~wR+1)) );
        
            ASSERT(aStartPos > posL);
            ASSERT(posR > aStartPos);
            const TUint32 distL = aStartPos-posL;
            const TUint32 distR = posR-aStartPos;

            if(distL < distR)
            {
                aStartPos = posL;
                return ETrue;
            }
            else if(distL > distR)
            {
                aStartPos = posR;
                return ETrue;
            }
            else
            {//-- distL == distR, take into account search priority
                aStartPos = aToLeft ? posL : posR;
                return ETrue;
            }

        }//else if(wL && wR)


        if(noWayLeft)
        {
            aStartPos = r_Idx << 5;
            return FindToRight(aStartPos, aBitVal);
        }
        else
        {
            noWayLeft  = ItrLeft(l_Idx);
        }

        if(noWayRight)
        {
            aStartPos = l_Idx << 5;
            return FindToLeft(aStartPos, aBitVal);
        }
        else
        {    
            noWayRight = ItrRight(r_Idx);
        }

   }//for(;;)

    //return EFalse;
}

//-----------------------------------------------------------------------------
/**
    Find out if two vectors are different.

    @param  aRhs        vector to compare with
    @param  aDiffIndex  if there is a differene, here will be the number of the first different bit
    @return ETrue if vectors differ, EFalse, if they are identical.
*/
TBool RBitVector::Diff(const RBitVector& aRhs, TUint32& aDiffIndex) const
{
    __ASSERT_ALWAYS(ipData, Panic(ENotInitialised));
    __ASSERT_ALWAYS(iNumBits == aRhs.iNumBits, Panic(ESizeMismatch));
    ASSERT(iNumWords > 0);

    TUint32 diffWord=0;
    TUint32 wordNum=0;

    //-- compare all but the last word in the array
    for(wordNum=0; wordNum < iNumWords-1; ++wordNum)
    {
        diffWord = ipData[wordNum] ^ aRhs.ipData[wordNum];
        if(diffWord)
            break;  //-- found difference
    }

    //-- process the last word in the array
    if(!diffWord)
    {
        diffWord = MaskLastWord(ipData[wordNum]) ^ MaskLastWord(aRhs.ipData[wordNum]);
    }

    if(!diffWord)
        return EFalse; //-- vectors are the same

    //-- calculate the position of the bit that different.
    diffWord &= (~diffWord+1); //-- select rightmost bit
    aDiffIndex = (wordNum << 5)+Log2(diffWord);
    
    return ETrue;
}
//-----------------------------------------------------------------------------

/**
    Iterate to the left (towards lower index) in the array of words ipData

    @param  aIdx index within ipData array to be decremented; if it's possible to move left, it will be decreased
    @return ETrue if there is no way left i.e. aIdx is 0. EFalse otherwise and aIdx decreased.
*/
TBool RBitVector::ItrLeft(TUint32& aIdx) const
{
    if(aIdx == 0)
        return ETrue;
    else
    {
        aIdx--;
        return EFalse;
    }
}


/**
    Iterate to the right (towards higher index) in the array of words ipData

    @param  aIdx index within ipData array to be incremented; if it's possible to move right, it will be increased
    @return ETrue if there is no way right i.e. aIdx corresponds to the last word. EFalse otherwise and aIdx increased.
*/
TBool RBitVector::ItrRight(TUint32& aIdx) const
{
    if(aIdx < iNumWords-1)
    {
        aIdx++;
        return EFalse;
    }
    else
        return ETrue;
}