diff -r 000000000000 -r a41df078684a userlibandfileserver/fileserver/sfsrv/cl_cdir.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/userlibandfileserver/fileserver/sfsrv/cl_cdir.cpp Mon Oct 19 15:55:17 2009 +0100 @@ -0,0 +1,569 @@ +// Copyright (c) 1995-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: +// f32\sfsrv\cl_cdir.cpp +// +// + +#include "cl_std.h" +#include + +const TUint KCDirArrayGranularity=0x200; +const TInt KPartKeyLength = 8; +const TInt KCollationLevel0 = 0; +const TInt KCollationLevelMax = 3; + +#define KCollationKeyAllocFail ((HBufC8*)-1) + +/////////////////////////////////////////////////////////////////////////////// +/** + * @class TEntry2 + * @description TEntry's variant with pointer to collation key buffers + * @internalComponent + */ +NONSHARABLE_CLASS(TEntry2) + { +public: + TEntry2(const TEntry& aEntry); + ~TEntry2(); +public: + TBool IsDir() const {return iEntry.IsDir();} +#ifndef SYMBIAN_ENABLE_64_BIT_FILE_SERVER_API + TInt64 Size() {return MAKE_TINT64(0,iEntry.iSize);} +#else + TInt64 Size() {return iEntry.FileSize();} +#endif + TTime Modified() const {return iEntry.iModified;} + const TUidType& Type() const {return iEntry.iType;} + const TDesC& Name() const {return iEntry.iName;} +private: + TEntry2(const TEntry2& aEntry); + TEntry2& operator=(const TEntry2& aEntry); +public: + HBufC8* iPartKey; + HBufC8* iFullKey; + TEntry iEntry; + }; + +TEntry2::TEntry2(const TEntry& aEntry) : iPartKey(0), iFullKey(0), iEntry(aEntry) + { + } + +TEntry2::~TEntry2() + { + if (iPartKey != KCollationKeyAllocFail) + delete iPartKey; + if (iFullKey != KCollationKeyAllocFail) + delete iFullKey; + } + +inline TInt Entry2Size(const TEntry2& aEntry) + { + return sizeof(HBufC8*) * 2 + EntrySize(aEntry.iEntry, ETrue); + } +/////////////////////////////////////////////////////////////////////////////// + +NONSHARABLE_CLASS(TKeyDir) : public TKeyArrayVar + { +public: + TKeyDir(TUint aKey); + virtual TInt Compare(TInt aLeft,TInt aRight) const; +private: + TInt CompareByName(TEntry2& aLeft, TEntry2& aRight) const; +private: + TCollationMethod iCollationMethod; + }; + +TKeyDir::TKeyDir(TUint aKey) +// +// Constructor +// + : TKeyArrayVar(0,(TKeyCmpText)(aKey&0xff),aKey&(EDirsFirst|EDirsLast|EDescending|EDirDescending)) + { + // + // Create our own collation method to also consider punctuation when + // sorting filenames. + // + iCollationMethod = *Mem::GetDefaultMatchingTable(); + iCollationMethod.iFlags |= TCollationMethod::EIgnoreNone | TCollationMethod::EFoldCase; + } + + +TInt TKeyDir::Compare(TInt aLeft,TInt aRight) const +// +// Compare two directories for sorting. +// + { + + if (aLeft==aRight) + return(0); + TEntry2& left = *(TEntry2*)At(aLeft); + TEntry2& right = *(TEntry2*)At(aRight); + TInt ret=0; + if ((iKeyLength&EDirsFirst)==EDirsFirst) + { + if (left.IsDir()) + { + if (!right.IsDir()) + ret=(-1); // left is a dir, right is not + } + else if (right.IsDir()) + ret=1; // right is a dir, left is not + } + else if ((iKeyLength&EDirsLast)==EDirsLast) + { + if (left.IsDir()) + { + if (!right.IsDir()) + ret=1; // left is a dir, right is not + } + else if (right.IsDir()) + ret=(-1); // right is a dir, left is not + } + + TInt cmpType=iCmpType; + TInt keyLength=iKeyLength; + TBool orderDirectories=(keyLength&EDirsFirst) || (keyLength&EDirsLast); + if (orderDirectories && left.IsDir() && right.IsDir()) + { + cmpType=ESortByName; + if ((keyLength&EDirDescending)!=EDirDescending) + keyLength&=~EDescending; + else + keyLength|=EDescending; + } + + if (ret==0) // Both are the same type + { + ret=(-1); // left before right by default + switch (cmpType) + { + case ESortNone: + ret=1; + break; + case ESortByDate: + if (left.Modified()>right.Modified()) + ret=1; + else if (left.Modified()==right.Modified()) + ret=0; + break; + case ESortBySize: +#ifndef SYMBIAN_ENABLE_64_BIT_FILE_SERVER_API + if (I64LOW(left.Size()) > I64LOW(right.Size())) + ret=1; + else if (I64LOW(left.Size())==I64LOW(right.Size())) + ret=0; +#else + if (left.Size() > right.Size()) + ret=1; + else if (left.Size()==right.Size()) + ret=0; +#endif + break; + case ESortByExt: + { + TInt i1 = KErrNotFound, i2 = KErrNotFound; + if (left.Name() != _L(".") && left.Name() != _L("..")) + i1 = left.Name().LocateReverse('.'); + if (right.Name() != _L(".") && right.Name() != _L("..")) + i2 = right.Name().LocateReverse('.'); + if (i1==KErrNotFound && i2!=KErrNotFound) + ret=(-1); + else if (i2==KErrNotFound && i1!=KErrNotFound) + ret=1; + else if ((i1==KErrNotFound && i2==KErrNotFound) || (ret=left.Name().Mid(i1).CompareC(right.Name().Mid(i2)))==0) + goto byName; + } + break; + case ESortByUid: + if (left.Type()[1]==right.Type()[1]) + { + if (left.Type()[2]==right.Type()[2]) + ret = CompareByName(left, right); + else if (left.Type()[2].iUid>right.Type()[2].iUid) + ret=1; + } + else if (left.Type()[1].iUid==0) + ret=1; + else if (right.Type()[1].iUid==0) + ret=-1; + else if (left.Type()[1].iUid>right.Type()[1].iUid) + ret=1; + break; + case ESortByName: +byName: + // Force the maximum collation level here (i.e. 3) for sorting strings + ret = CompareByName(left, right); + break; + default: // Default is bad news + Panic(ECDirBadSortType); + } + } + if ((keyLength&EDescending)==EDescending) + ret=(-ret); // Descending sort order + return(ret); + } + +TInt TKeyDir::CompareByName(TEntry2& aLeft, TEntry2& aRight) const +// +// Compare using collation key of entire name +// + { + TInt ret = -1; + TInt r = KErrNone; + + // Allocate partial key first and handle potential error case + // by calling old CompareC + // Note: only compare on the first collation level (KCollationLevel0) for partial keys, + // to avoid potential inconsistency between full key and partial key comparison. + if (!aLeft.iPartKey) + { + TRAP(r, aLeft.iPartKey = aLeft.Name().Left(KPartKeyLength).GetCollationKeysL(KCollationLevel0, &iCollationMethod)); + if (r != KErrNone) + aLeft.iPartKey = KCollationKeyAllocFail; + } + if (!aRight.iPartKey) + { + TRAP(r, aRight.iPartKey = aRight.Name().Left(KPartKeyLength).GetCollationKeysL(KCollationLevel0, &iCollationMethod)); + if (r != KErrNone) + aRight.iPartKey = KCollationKeyAllocFail; + } + if (aLeft.iPartKey == KCollationKeyAllocFail || aRight.iPartKey == KCollationKeyAllocFail) + return aLeft.Name().CompareC(aRight.Name()); + + // Compare by partial key first + ret = aLeft.iPartKey->Compare(*aRight.iPartKey); + if (ret != 0) + return ret; + + // Compare by full key if partial keys are identical + if (!aLeft.iFullKey) + { + TRAP(r, aLeft.iFullKey = aLeft.Name().GetCollationKeysL(KCollationLevelMax, &iCollationMethod)); + if (r != KErrNone) + aLeft.iFullKey = KCollationKeyAllocFail; + } + if (!aRight.iFullKey) + { + TRAP(r, aRight.iFullKey = aRight.Name().GetCollationKeysL(KCollationLevelMax, &iCollationMethod)); + if (r != KErrNone) + aRight.iFullKey = KCollationKeyAllocFail; + } + if (aLeft.iFullKey == KCollationKeyAllocFail || aRight.iFullKey == KCollationKeyAllocFail) + // Using old CompareC if partial key allocation failed + return aLeft.Name().CompareC(aRight.Name()); + + // Compare using collation key of full names + ret = aLeft.iFullKey->Compare(*aRight.iFullKey); + + return ret; + } + + + +EXPORT_C CDir::CDir() +/** +Default constructor. +*/ + { + } + + + + +EXPORT_C CDir::~CDir() +/** +Destructor. + +Frees all resources owned by the object, prior to its destruction. +*/ + { + + delete iArray; + } + + + + +EXPORT_C CDir* CDir::NewL() +/** +Allocates and constructs a directory object. + +This function is protected, which prevents objects of this class from being +directly constructed. + +@return A pointer to the newly created object. +*/ + { + + CDir* pD=new(ELeave) CDir; + pD->iArray=new CArrayPakFlat(KCDirArrayGranularity); + if (pD->iArray==NULL) + { + delete pD; + User::LeaveNoMemory(); + } + return(pD); + } + + + + +EXPORT_C TInt CDir::Count() const +/** +Gets the number of entries in the array of directory +entries. + +@return The number of entries in the array. +*/ + { + + return(iArray->Count()); + } + + + + +EXPORT_C const TEntry& CDir::operator[](TInt anIndex) const +/** +Gets an entry from the array of directory +entries. + +@param anIndex of the desired entry within the array. + +@return A directory entry. +*/ + { + + return((*iArray)[anIndex]); + } + + +/** + * Utility class to manage dynamic array memory + * @internalComponent + */ +NONSHARABLE_CLASS(CAutoArray) : public CBase + { +public: + ~CAutoArray(); +public: + CArrayVarFlat* iArray; + }; + +// Have to do this trick because CArrayVarFlat won't destroy element one by one +CAutoArray::~CAutoArray() + { + if (iArray) + for (TInt i=0; iCount(); ++i) + { + TEntry2& e = (*iArray)[i]; + if (e.iPartKey != KCollationKeyAllocFail) + delete e.iPartKey; + if (e.iFullKey != KCollationKeyAllocFail) + delete e.iFullKey; + e.iPartKey = e.iFullKey = 0; + } + delete iArray; + } + +EXPORT_C TInt CDir::Sort(TUint aKey) +/** +Sorts the array of directory entries. + +@param aKey A set of flags describing how the directory entries are to be sorted. + The set of flags is defined by TEntryKey. + +@return KErrNone, if successful, otherwise one of the other system-wide error + codes. + +@see TEntryKey +*/ + { + CAutoArray autoArray; + #define array autoArray.iArray + + // Create TEntry2 array from iArray. + array = new CArrayVarFlat(KCDirArrayGranularity); + if (!array) + return KErrNoMemory; + + TInt arrayCount = iArray->Count(); + if (arrayCount == 0) + return KErrNone; + + TEntry2* entry2 = new TEntry2((*iArray)[0]); + + if (!entry2) + return KErrNoMemory; + + TInt i, r; + for (i=0; iiEntry = (*iArray)[i]; + // Pack here + TUint32* pSizeHighSrc = PtrAdd((TUint32*)&(entry2->iEntry), sizeof(TEntry) - 2 * sizeof(TInt)); + TUint32* pSizeHighDst = PtrAdd((TUint32*)&(entry2->iEntry), EntrySize(entry2->iEntry, EFalse)); + + *pSizeHighDst++ = *pSizeHighSrc++; // Pack iSizeHigh + *pSizeHighDst = *pSizeHighSrc; // Pack iReserved + entry2->iEntry.iAtt |= KEntryAttPacked; + + TRAP(r, array->AppendL(*entry2, Entry2Size(*entry2))); + + if (r != KErrNone) + { + delete entry2; + return r; + } + } + + // Sort new array + TKeyDir key(aKey); + r = array->Sort(key); + if (r != KErrNone) + { + delete entry2; + return r; + } + + // Copy sorted result back to iArray + iArray->Reset(); + + for (i=0; iCount(); ++i) + { + entry2->iEntry = (*array)[i].iEntry; + // Pack here + TUint32* pSizeHighSrc = PtrAdd((TUint32*)&(entry2->iEntry), sizeof(TEntry) - 2 * sizeof(TInt)); + TUint32* pSizeHighDst = PtrAdd((TUint32*)&(entry2->iEntry), EntrySize(entry2->iEntry, EFalse)); + + *pSizeHighDst++ = *pSizeHighSrc++; // Pack iSizeHigh + *pSizeHighDst = *pSizeHighSrc; // Pack iReserved + entry2->iEntry.iAtt |= KEntryAttPacked; + + TRAP(r, iArray->AppendL(entry2->iEntry, EntrySize(entry2->iEntry, ETrue))); + if (r != KErrNone) + { + delete entry2; + return r; + } + } + + delete entry2; + return r; + } + + +EXPORT_C void CDir::AddL(const TEntry& aEntry) +/** +Adds the specified entry to the directory. + +Note that the function can leave. + +@param aEntry The directory entry to be added. +*/ + { + if(aEntry.iAtt & KEntryAttPacked) + { + iArray->AppendL(aEntry,EntrySize(aEntry, ETrue)); + } + else + { + TEntry entry = aEntry; + // Pack here + TUint32* pSizeHighSrc = PtrAdd((TUint32*)&entry, sizeof(TEntry) - 2 * sizeof(TInt)); + TUint32* pSizeHighDst = PtrAdd((TUint32*)&entry, EntrySize(entry, EFalse)); + + *pSizeHighDst++ = *pSizeHighSrc++; // Pack iSizeHigh + *pSizeHighDst = *pSizeHighSrc; // Pack iReserved + entry.iAtt |= KEntryAttPacked; + iArray->AppendL(entry,EntrySize(entry, ETrue)); + } + } + + + + +EXPORT_C void CDir::ExtractL(TBool aRemove,CDir* & aDir) +/** +Copies all directory entries from this directory array, and adds them to +a new directory array. + +The directory entries in this array can be deleted. + +Note that the function can leave. + +@param aRemove If ETrue, the directory entries in this array are + to be deleted after extraction; + if EFalse, the directory entries are not to be deleted. + +@param aDir On return, a pointer to a CDir object containing + the extracted directory entries. +*/ + { + + aDir=NULL; + aDir=CDir::NewL(); + CArrayPakFlat& anArray=(*iArray); + TInt count=anArray.Count(); + + if (count == 0) + return; + + TInt i=0; + while (iAddL(e); + i++; + } + if (aRemove) + { + i=0; + while (iCompress(); + } + + + + +EXPORT_C void CDir::Compress() +/** +Compresses the directory. + +This has the effect of potentially reducing the ammount of storage +space required on the media for that directory and the files it contains. +Some files are already compressed and will not compress further. + +A potential side effect of compression is that each file is required to +be uncompressed prior to use, generally increasing the time and +processing cycles required to access that file. + +*/ + { + + iArray->Compress(); + } +