os/kernelhwsrv/userlibandfileserver/fileserver/sfsrv/cl_cdir.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     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