userlibandfileserver/fileserver/sfsrv/cl_cdir.cpp
changeset 0 a41df078684a
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of the License "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // f32\sfsrv\cl_cdir.cpp
       
    15 // 
       
    16 //
       
    17 
       
    18 #include "cl_std.h"
       
    19 #include <collate.h>
       
    20 
       
    21 const TUint KCDirArrayGranularity=0x200;
       
    22 const TInt KPartKeyLength = 8;
       
    23 const TInt KCollationLevel0 = 0;
       
    24 const TInt KCollationLevelMax = 3;
       
    25 
       
    26 #define KCollationKeyAllocFail ((HBufC8*)-1)
       
    27 
       
    28 ///////////////////////////////////////////////////////////////////////////////
       
    29 /**
       
    30  * @class TEntry2
       
    31  * @description TEntry's variant with pointer to collation key buffers
       
    32  * @internalComponent
       
    33  */
       
    34 NONSHARABLE_CLASS(TEntry2)
       
    35     {
       
    36 public:
       
    37 	TEntry2(const TEntry& aEntry);
       
    38 	~TEntry2();
       
    39 public:
       
    40     TBool IsDir() const {return iEntry.IsDir();}
       
    41 #ifndef	SYMBIAN_ENABLE_64_BIT_FILE_SERVER_API
       
    42     TInt64 Size() {return MAKE_TINT64(0,iEntry.iSize);}
       
    43 #else
       
    44     TInt64 Size() {return iEntry.FileSize();}
       
    45 #endif
       
    46     TTime Modified() const {return iEntry.iModified;}
       
    47     const TUidType& Type() const {return iEntry.iType;}
       
    48     const TDesC& Name() const {return iEntry.iName;}
       
    49 private:
       
    50     TEntry2(const TEntry2& aEntry);
       
    51     TEntry2& operator=(const TEntry2& aEntry);
       
    52 public:
       
    53 	HBufC8* iPartKey;
       
    54 	HBufC8* iFullKey;
       
    55 	TEntry iEntry;
       
    56     };
       
    57 
       
    58 TEntry2::TEntry2(const TEntry& aEntry) : iPartKey(0), iFullKey(0), iEntry(aEntry)
       
    59 	{
       
    60 	}
       
    61 
       
    62 TEntry2::~TEntry2()
       
    63 	{
       
    64 	if (iPartKey != KCollationKeyAllocFail)
       
    65         delete iPartKey;
       
    66 	if (iFullKey != KCollationKeyAllocFail)
       
    67 	    delete iFullKey;
       
    68 	}
       
    69 
       
    70 inline TInt Entry2Size(const TEntry2& aEntry)
       
    71     {
       
    72     return sizeof(HBufC8*) * 2 + EntrySize(aEntry.iEntry, ETrue);
       
    73     }
       
    74 ///////////////////////////////////////////////////////////////////////////////
       
    75 
       
    76 NONSHARABLE_CLASS(TKeyDir) : public TKeyArrayVar
       
    77 	{
       
    78 public:
       
    79 	TKeyDir(TUint aKey);
       
    80 	virtual TInt Compare(TInt aLeft,TInt aRight) const;
       
    81 private:
       
    82 	TInt CompareByName(TEntry2& aLeft, TEntry2& aRight) const;
       
    83 private:
       
    84 	TCollationMethod iCollationMethod;
       
    85 	};
       
    86 
       
    87 TKeyDir::TKeyDir(TUint aKey)
       
    88 //
       
    89 // Constructor
       
    90 //
       
    91 	: TKeyArrayVar(0,(TKeyCmpText)(aKey&0xff),aKey&(EDirsFirst|EDirsLast|EDescending|EDirDescending))
       
    92 	{
       
    93 	//
       
    94 	// Create our own collation method to also consider punctuation when
       
    95 	// sorting filenames.
       
    96 	//
       
    97 	iCollationMethod = *Mem::GetDefaultMatchingTable();
       
    98 	iCollationMethod.iFlags |= TCollationMethod::EIgnoreNone | TCollationMethod::EFoldCase;
       
    99 	}
       
   100 
       
   101 
       
   102 TInt TKeyDir::Compare(TInt aLeft,TInt aRight) const
       
   103 //
       
   104 // Compare two directories for sorting.
       
   105 //
       
   106 	{
       
   107 
       
   108 	if (aLeft==aRight)
       
   109 		return(0);
       
   110 	TEntry2& left = *(TEntry2*)At(aLeft);
       
   111 	TEntry2& right = *(TEntry2*)At(aRight);
       
   112 	TInt ret=0;
       
   113 	if ((iKeyLength&EDirsFirst)==EDirsFirst)
       
   114 		{
       
   115 		if (left.IsDir())
       
   116 			{
       
   117 			if (!right.IsDir())
       
   118 				ret=(-1); // left is a dir, right is not
       
   119 			}
       
   120 		else if (right.IsDir())
       
   121 			ret=1; // right is a dir, left is not
       
   122 		}
       
   123 	else if ((iKeyLength&EDirsLast)==EDirsLast)
       
   124 		{
       
   125 		if (left.IsDir())
       
   126 			{
       
   127 			if (!right.IsDir())
       
   128 				ret=1; // left is a dir, right is not
       
   129 			}
       
   130 		else if (right.IsDir())
       
   131 			ret=(-1); // right is a dir, left is not
       
   132 		}
       
   133 
       
   134 	TInt cmpType=iCmpType;
       
   135 	TInt keyLength=iKeyLength;
       
   136 	TBool orderDirectories=(keyLength&EDirsFirst) || (keyLength&EDirsLast);
       
   137 	if (orderDirectories && left.IsDir() && right.IsDir())
       
   138 		{
       
   139 		cmpType=ESortByName;
       
   140 		if ((keyLength&EDirDescending)!=EDirDescending)
       
   141 			keyLength&=~EDescending;
       
   142 		else
       
   143 			keyLength|=EDescending;
       
   144 		}
       
   145 
       
   146 	if (ret==0) // Both are the same type
       
   147 		{
       
   148 		ret=(-1); // left before right by default
       
   149 		switch (cmpType)
       
   150 			{
       
   151 		case ESortNone:
       
   152 			ret=1;
       
   153 			break;
       
   154 		case ESortByDate:
       
   155 			if (left.Modified()>right.Modified())
       
   156 				ret=1;
       
   157 			else if (left.Modified()==right.Modified())
       
   158 				ret=0;
       
   159 			break;
       
   160 		case ESortBySize:
       
   161 #ifndef SYMBIAN_ENABLE_64_BIT_FILE_SERVER_API
       
   162 		if (I64LOW(left.Size()) > I64LOW(right.Size()))
       
   163 			ret=1;
       
   164 		else if (I64LOW(left.Size())==I64LOW(right.Size()))
       
   165 			ret=0;
       
   166 #else
       
   167 			if (left.Size() > right.Size())
       
   168 				ret=1;
       
   169 			else if (left.Size()==right.Size())
       
   170 				ret=0;
       
   171 #endif
       
   172 			break;
       
   173 		case ESortByExt:
       
   174 			{
       
   175 			TInt i1 = KErrNotFound, i2 = KErrNotFound;
       
   176 			if (left.Name() != _L(".") && left.Name() != _L(".."))
       
   177 				i1 = left.Name().LocateReverse('.');
       
   178 			if (right.Name() != _L(".") && right.Name() != _L(".."))
       
   179 				i2 = right.Name().LocateReverse('.');
       
   180 			if (i1==KErrNotFound && i2!=KErrNotFound)
       
   181 				ret=(-1);
       
   182 			else if (i2==KErrNotFound && i1!=KErrNotFound)
       
   183 				ret=1;
       
   184 			else if ((i1==KErrNotFound && i2==KErrNotFound) || (ret=left.Name().Mid(i1).CompareC(right.Name().Mid(i2)))==0)
       
   185 				goto byName;
       
   186 			}
       
   187 			break;
       
   188 		case ESortByUid:
       
   189 			if (left.Type()[1]==right.Type()[1])
       
   190 				{
       
   191 				if (left.Type()[2]==right.Type()[2])
       
   192 					ret = CompareByName(left, right);
       
   193 				else if (left.Type()[2].iUid>right.Type()[2].iUid)
       
   194 					ret=1;
       
   195 				}
       
   196 			else if (left.Type()[1].iUid==0)
       
   197 				ret=1;
       
   198 			else if (right.Type()[1].iUid==0)
       
   199 				ret=-1;
       
   200 			else if (left.Type()[1].iUid>right.Type()[1].iUid)
       
   201 				ret=1;
       
   202 			break;
       
   203 		case ESortByName:
       
   204 byName:
       
   205 			// Force the maximum collation level here (i.e. 3) for sorting strings 
       
   206 			ret = CompareByName(left, right);
       
   207 			break;
       
   208 		default: // Default is bad news
       
   209 			Panic(ECDirBadSortType);
       
   210 			}
       
   211 		}
       
   212 	if ((keyLength&EDescending)==EDescending)
       
   213 		ret=(-ret); // Descending sort order
       
   214 	return(ret);
       
   215 	}
       
   216 
       
   217 TInt TKeyDir::CompareByName(TEntry2& aLeft, TEntry2& aRight) const
       
   218 //
       
   219 // Compare using collation key of entire name
       
   220 //
       
   221 	{
       
   222 	TInt ret = -1;
       
   223 	TInt r = KErrNone;
       
   224 
       
   225     // Allocate partial key first and handle potential error case
       
   226     // by calling old CompareC
       
   227 	// Note: only compare on the first collation level (KCollationLevel0) for partial keys, 
       
   228 	//       to avoid potential inconsistency between full key and partial key comparison.
       
   229 	if (!aLeft.iPartKey)
       
   230 		{
       
   231 		TRAP(r, aLeft.iPartKey = aLeft.Name().Left(KPartKeyLength).GetCollationKeysL(KCollationLevel0, &iCollationMethod));
       
   232 		if (r != KErrNone)
       
   233 		    aLeft.iPartKey = KCollationKeyAllocFail;
       
   234 		}
       
   235 	if (!aRight.iPartKey)
       
   236 		{
       
   237 		TRAP(r, aRight.iPartKey = aRight.Name().Left(KPartKeyLength).GetCollationKeysL(KCollationLevel0, &iCollationMethod));
       
   238 		if (r != KErrNone)
       
   239 		    aRight.iPartKey = KCollationKeyAllocFail;
       
   240 		}
       
   241 	if (aLeft.iPartKey == KCollationKeyAllocFail || aRight.iPartKey == KCollationKeyAllocFail)
       
   242 		return aLeft.Name().CompareC(aRight.Name());
       
   243 
       
   244 	// Compare by partial key first
       
   245     ret = aLeft.iPartKey->Compare(*aRight.iPartKey);
       
   246     if (ret != 0)
       
   247         return ret;
       
   248 
       
   249     // Compare by full key if partial keys are identical
       
   250 	if (!aLeft.iFullKey)
       
   251 		{
       
   252 		TRAP(r, aLeft.iFullKey = aLeft.Name().GetCollationKeysL(KCollationLevelMax, &iCollationMethod));
       
   253 		if (r != KErrNone)
       
   254 		    aLeft.iFullKey = KCollationKeyAllocFail;
       
   255 		}
       
   256 	if (!aRight.iFullKey)
       
   257 		{
       
   258 		TRAP(r, aRight.iFullKey = aRight.Name().GetCollationKeysL(KCollationLevelMax, &iCollationMethod));
       
   259 		if (r != KErrNone)
       
   260 		    aRight.iFullKey = KCollationKeyAllocFail;
       
   261 		}
       
   262 	if (aLeft.iFullKey == KCollationKeyAllocFail || aRight.iFullKey == KCollationKeyAllocFail)
       
   263 	    // Using old CompareC if partial key allocation failed
       
   264 		return aLeft.Name().CompareC(aRight.Name());
       
   265 
       
   266     // Compare using collation key of full names
       
   267     ret = aLeft.iFullKey->Compare(*aRight.iFullKey);
       
   268 
       
   269 	return ret;
       
   270 	}
       
   271 
       
   272 
       
   273 
       
   274 EXPORT_C CDir::CDir()
       
   275 /**
       
   276 Default constructor.
       
   277 */
       
   278 	{
       
   279 	}
       
   280 
       
   281 
       
   282 
       
   283 
       
   284 EXPORT_C CDir::~CDir()
       
   285 /**
       
   286 Destructor.
       
   287 
       
   288 Frees all resources owned by the object, prior to its destruction.
       
   289 */
       
   290 	{
       
   291 
       
   292 	delete iArray;
       
   293 	}
       
   294 
       
   295 
       
   296 
       
   297 
       
   298 EXPORT_C CDir* CDir::NewL()
       
   299 /**
       
   300 Allocates and constructs a directory object.
       
   301 
       
   302 This function is protected, which prevents objects of this class from being
       
   303 directly constructed.
       
   304 
       
   305 @return A pointer to the newly created object.
       
   306 */
       
   307 	{
       
   308 
       
   309 	CDir* pD=new(ELeave) CDir;
       
   310 	pD->iArray=new CArrayPakFlat<TEntry>(KCDirArrayGranularity);
       
   311 	if (pD->iArray==NULL)
       
   312 		{
       
   313 		delete pD;
       
   314 		User::LeaveNoMemory();
       
   315 		}
       
   316 	return(pD);
       
   317 	}
       
   318 
       
   319 
       
   320 
       
   321 
       
   322 EXPORT_C TInt CDir::Count() const
       
   323 /**
       
   324 Gets the number of entries in the array of directory
       
   325 entries.
       
   326 
       
   327 @return The number of entries in the array.
       
   328 */
       
   329 	{
       
   330 
       
   331 	return(iArray->Count());
       
   332 	}
       
   333 
       
   334 
       
   335 
       
   336 
       
   337 EXPORT_C const TEntry& CDir::operator[](TInt anIndex) const
       
   338 /**
       
   339 Gets an entry from the array of directory
       
   340 entries.
       
   341 
       
   342 @param anIndex of the desired entry within the array.
       
   343 
       
   344 @return A directory entry.
       
   345 */
       
   346 	{
       
   347 
       
   348 	return((*iArray)[anIndex]);
       
   349 	}
       
   350 
       
   351 
       
   352 /**
       
   353  * Utility class to manage dynamic array memory
       
   354  * @internalComponent
       
   355  */
       
   356 NONSHARABLE_CLASS(CAutoArray) : public CBase
       
   357     {
       
   358 public:
       
   359     ~CAutoArray();
       
   360 public:
       
   361     CArrayVarFlat<TEntry2>* iArray;
       
   362     };
       
   363 
       
   364 // Have to do this trick because CArrayVarFlat won't destroy element one by one
       
   365 CAutoArray::~CAutoArray()
       
   366     {
       
   367     if (iArray)
       
   368         for (TInt i=0; i<iArray->Count(); ++i)
       
   369             {
       
   370             TEntry2& e = (*iArray)[i];
       
   371            	if (e.iPartKey != KCollationKeyAllocFail)
       
   372                 delete e.iPartKey;
       
   373 	        if (e.iFullKey != KCollationKeyAllocFail)
       
   374 	            delete e.iFullKey;
       
   375             e.iPartKey = e.iFullKey = 0;
       
   376             }
       
   377     delete iArray;
       
   378     }
       
   379 
       
   380 EXPORT_C TInt CDir::Sort(TUint aKey)
       
   381 /**
       
   382 Sorts the array of directory entries.
       
   383 
       
   384 @param aKey A set of flags describing how the directory entries are to be sorted.
       
   385        The set of flags is defined by TEntryKey.
       
   386 
       
   387 @return KErrNone, if successful, otherwise one of the other	 system-wide error
       
   388         codes.
       
   389 
       
   390 @see TEntryKey
       
   391 */
       
   392 	{
       
   393 	CAutoArray autoArray;
       
   394 	#define array autoArray.iArray
       
   395 
       
   396 	// Create TEntry2 array from iArray.
       
   397 	array = new CArrayVarFlat<TEntry2>(KCDirArrayGranularity);
       
   398 	if (!array)
       
   399 		return KErrNoMemory;
       
   400 	
       
   401 	TInt arrayCount = iArray->Count();
       
   402 	if (arrayCount == 0)
       
   403 		return KErrNone;
       
   404 	
       
   405 	TEntry2* entry2 = new TEntry2((*iArray)[0]);
       
   406 	
       
   407 	if (!entry2)
       
   408 		return KErrNoMemory;
       
   409 
       
   410 	TInt i, r;
       
   411 	for (i=0; i<arrayCount; ++i)
       
   412 		{
       
   413 		entry2->iEntry = (*iArray)[i];
       
   414 		// Pack here
       
   415 		TUint32* pSizeHighSrc = PtrAdd((TUint32*)&(entry2->iEntry), sizeof(TEntry) - 2 * sizeof(TInt));
       
   416 		TUint32* pSizeHighDst = PtrAdd((TUint32*)&(entry2->iEntry), EntrySize(entry2->iEntry, EFalse));
       
   417 		
       
   418 		*pSizeHighDst++ = *pSizeHighSrc++;	// Pack iSizeHigh
       
   419 		*pSizeHighDst   = *pSizeHighSrc;	// Pack iReserved
       
   420 		entry2->iEntry.iAtt |= KEntryAttPacked;
       
   421 		
       
   422 		TRAP(r, array->AppendL(*entry2, Entry2Size(*entry2)));
       
   423 
       
   424 		if (r != KErrNone)
       
   425 			{
       
   426 			delete entry2;	
       
   427 			return r;
       
   428 			}
       
   429 		}
       
   430 
       
   431 	// Sort new array
       
   432 	TKeyDir key(aKey);
       
   433 	r = array->Sort(key);
       
   434 	if (r != KErrNone)
       
   435 		{
       
   436 		delete entry2;
       
   437         return r;
       
   438 		}
       
   439 
       
   440 	// Copy sorted result back to iArray
       
   441 	iArray->Reset();
       
   442 	
       
   443 	for (i=0; i<array->Count(); ++i)
       
   444 		{
       
   445 		entry2->iEntry = (*array)[i].iEntry;
       
   446 		// Pack here
       
   447 		TUint32* pSizeHighSrc = PtrAdd((TUint32*)&(entry2->iEntry), sizeof(TEntry) - 2 * sizeof(TInt));
       
   448 		TUint32* pSizeHighDst = PtrAdd((TUint32*)&(entry2->iEntry), EntrySize(entry2->iEntry, EFalse));
       
   449 		
       
   450 		*pSizeHighDst++ = *pSizeHighSrc++;	// Pack iSizeHigh
       
   451 		*pSizeHighDst   = *pSizeHighSrc;	// Pack iReserved
       
   452 		entry2->iEntry.iAtt |= KEntryAttPacked;
       
   453 		
       
   454 		TRAP(r, iArray->AppendL(entry2->iEntry, EntrySize(entry2->iEntry, ETrue)));
       
   455 		if (r != KErrNone)
       
   456 			{
       
   457 			delete entry2;	
       
   458 			return r;
       
   459 			}
       
   460 		}
       
   461 
       
   462 	delete entry2;
       
   463 	return r;
       
   464 	}
       
   465 	
       
   466 
       
   467 EXPORT_C void CDir::AddL(const TEntry& aEntry)
       
   468 /**
       
   469 Adds the specified entry to the directory.
       
   470 
       
   471 Note that the function can leave.
       
   472 
       
   473 @param aEntry The directory entry to be added.
       
   474 */
       
   475 	{
       
   476 	if(aEntry.iAtt & KEntryAttPacked)
       
   477 		{
       
   478 		iArray->AppendL(aEntry,EntrySize(aEntry, ETrue));
       
   479 		}
       
   480 	else
       
   481 		{
       
   482 		TEntry entry = aEntry;
       
   483 		// Pack here
       
   484 		TUint32* pSizeHighSrc = PtrAdd((TUint32*)&entry, sizeof(TEntry) - 2 * sizeof(TInt));
       
   485 		TUint32* pSizeHighDst = PtrAdd((TUint32*)&entry, EntrySize(entry, EFalse));
       
   486 		
       
   487 		*pSizeHighDst++ = *pSizeHighSrc++;	// Pack iSizeHigh
       
   488 		*pSizeHighDst   = *pSizeHighSrc;		// Pack iReserved
       
   489 		entry.iAtt |= KEntryAttPacked;
       
   490 		iArray->AppendL(entry,EntrySize(entry, ETrue));
       
   491 		}
       
   492 	}
       
   493 
       
   494 
       
   495 
       
   496 
       
   497 EXPORT_C void CDir::ExtractL(TBool aRemove,CDir* & aDir)
       
   498 /**
       
   499 Copies all directory entries from this directory array, and adds them to
       
   500 a new directory array.
       
   501 
       
   502 The directory entries in this array can be deleted.
       
   503 
       
   504 Note that the function can leave.
       
   505 
       
   506 @param aRemove If ETrue, the  directory entries in this array are
       
   507                to be deleted after extraction;
       
   508                if EFalse, the directory entries are not to be deleted.
       
   509                 
       
   510 @param aDir    On return, a pointer to a CDir object containing
       
   511                the extracted directory entries.
       
   512 */
       
   513 	{
       
   514 
       
   515 	aDir=NULL;
       
   516 	aDir=CDir::NewL();
       
   517 	CArrayPakFlat<TEntry>& anArray=(*iArray);
       
   518 	TInt count=anArray.Count();
       
   519 	
       
   520 	if (count == 0)
       
   521 		return;
       
   522 	
       
   523 	TInt i=0;
       
   524 	while (i<count)
       
   525 		{
       
   526 		TEntry& e=anArray[i];
       
   527 		if (e.IsDir())
       
   528 			aDir->AddL(e);
       
   529 		i++;
       
   530 		}
       
   531 	if (aRemove)
       
   532 		{
       
   533 		i=0;
       
   534 		while (i<count)
       
   535 			{
       
   536 			if (anArray[i].IsDir())
       
   537 				{
       
   538 				anArray.Delete(i);
       
   539 				count--;
       
   540 				continue;
       
   541 				}
       
   542 			i++;
       
   543 			}
       
   544 		anArray.Compress();
       
   545 		}
       
   546 	aDir->Compress();
       
   547 	}
       
   548 
       
   549 
       
   550 
       
   551 
       
   552 EXPORT_C void CDir::Compress()
       
   553 /**
       
   554 Compresses the directory.
       
   555 
       
   556 This has the effect of potentially reducing the ammount of storage 
       
   557 space required on the media for that directory and the files it contains. 
       
   558 Some files are already compressed and will not compress further.
       
   559 
       
   560 A potential side effect of compression is that each file is required to 
       
   561 be uncompressed prior to use, generally increasing the time and 
       
   562 processing cycles required to access that file.
       
   563 
       
   564 */
       
   565 	{
       
   566 
       
   567 	iArray->Compress();
       
   568 	}
       
   569