1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/userlibandfileserver/fileserver/sfsrv/cl_cdir.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,569 @@
1.4 +// Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// f32\sfsrv\cl_cdir.cpp
1.18 +//
1.19 +//
1.20 +
1.21 +#include "cl_std.h"
1.22 +#include <collate.h>
1.23 +
1.24 +const TUint KCDirArrayGranularity=0x200;
1.25 +const TInt KPartKeyLength = 8;
1.26 +const TInt KCollationLevel0 = 0;
1.27 +const TInt KCollationLevelMax = 3;
1.28 +
1.29 +#define KCollationKeyAllocFail ((HBufC8*)-1)
1.30 +
1.31 +///////////////////////////////////////////////////////////////////////////////
1.32 +/**
1.33 + * @class TEntry2
1.34 + * @description TEntry's variant with pointer to collation key buffers
1.35 + * @internalComponent
1.36 + */
1.37 +NONSHARABLE_CLASS(TEntry2)
1.38 + {
1.39 +public:
1.40 + TEntry2(const TEntry& aEntry);
1.41 + ~TEntry2();
1.42 +public:
1.43 + TBool IsDir() const {return iEntry.IsDir();}
1.44 +#ifndef SYMBIAN_ENABLE_64_BIT_FILE_SERVER_API
1.45 + TInt64 Size() {return MAKE_TINT64(0,iEntry.iSize);}
1.46 +#else
1.47 + TInt64 Size() {return iEntry.FileSize();}
1.48 +#endif
1.49 + TTime Modified() const {return iEntry.iModified;}
1.50 + const TUidType& Type() const {return iEntry.iType;}
1.51 + const TDesC& Name() const {return iEntry.iName;}
1.52 +private:
1.53 + TEntry2(const TEntry2& aEntry);
1.54 + TEntry2& operator=(const TEntry2& aEntry);
1.55 +public:
1.56 + HBufC8* iPartKey;
1.57 + HBufC8* iFullKey;
1.58 + TEntry iEntry;
1.59 + };
1.60 +
1.61 +TEntry2::TEntry2(const TEntry& aEntry) : iPartKey(0), iFullKey(0), iEntry(aEntry)
1.62 + {
1.63 + }
1.64 +
1.65 +TEntry2::~TEntry2()
1.66 + {
1.67 + if (iPartKey != KCollationKeyAllocFail)
1.68 + delete iPartKey;
1.69 + if (iFullKey != KCollationKeyAllocFail)
1.70 + delete iFullKey;
1.71 + }
1.72 +
1.73 +inline TInt Entry2Size(const TEntry2& aEntry)
1.74 + {
1.75 + return sizeof(HBufC8*) * 2 + EntrySize(aEntry.iEntry, ETrue);
1.76 + }
1.77 +///////////////////////////////////////////////////////////////////////////////
1.78 +
1.79 +NONSHARABLE_CLASS(TKeyDir) : public TKeyArrayVar
1.80 + {
1.81 +public:
1.82 + TKeyDir(TUint aKey);
1.83 + virtual TInt Compare(TInt aLeft,TInt aRight) const;
1.84 +private:
1.85 + TInt CompareByName(TEntry2& aLeft, TEntry2& aRight) const;
1.86 +private:
1.87 + TCollationMethod iCollationMethod;
1.88 + };
1.89 +
1.90 +TKeyDir::TKeyDir(TUint aKey)
1.91 +//
1.92 +// Constructor
1.93 +//
1.94 + : TKeyArrayVar(0,(TKeyCmpText)(aKey&0xff),aKey&(EDirsFirst|EDirsLast|EDescending|EDirDescending))
1.95 + {
1.96 + //
1.97 + // Create our own collation method to also consider punctuation when
1.98 + // sorting filenames.
1.99 + //
1.100 + iCollationMethod = *Mem::GetDefaultMatchingTable();
1.101 + iCollationMethod.iFlags |= TCollationMethod::EIgnoreNone | TCollationMethod::EFoldCase;
1.102 + }
1.103 +
1.104 +
1.105 +TInt TKeyDir::Compare(TInt aLeft,TInt aRight) const
1.106 +//
1.107 +// Compare two directories for sorting.
1.108 +//
1.109 + {
1.110 +
1.111 + if (aLeft==aRight)
1.112 + return(0);
1.113 + TEntry2& left = *(TEntry2*)At(aLeft);
1.114 + TEntry2& right = *(TEntry2*)At(aRight);
1.115 + TInt ret=0;
1.116 + if ((iKeyLength&EDirsFirst)==EDirsFirst)
1.117 + {
1.118 + if (left.IsDir())
1.119 + {
1.120 + if (!right.IsDir())
1.121 + ret=(-1); // left is a dir, right is not
1.122 + }
1.123 + else if (right.IsDir())
1.124 + ret=1; // right is a dir, left is not
1.125 + }
1.126 + else if ((iKeyLength&EDirsLast)==EDirsLast)
1.127 + {
1.128 + if (left.IsDir())
1.129 + {
1.130 + if (!right.IsDir())
1.131 + ret=1; // left is a dir, right is not
1.132 + }
1.133 + else if (right.IsDir())
1.134 + ret=(-1); // right is a dir, left is not
1.135 + }
1.136 +
1.137 + TInt cmpType=iCmpType;
1.138 + TInt keyLength=iKeyLength;
1.139 + TBool orderDirectories=(keyLength&EDirsFirst) || (keyLength&EDirsLast);
1.140 + if (orderDirectories && left.IsDir() && right.IsDir())
1.141 + {
1.142 + cmpType=ESortByName;
1.143 + if ((keyLength&EDirDescending)!=EDirDescending)
1.144 + keyLength&=~EDescending;
1.145 + else
1.146 + keyLength|=EDescending;
1.147 + }
1.148 +
1.149 + if (ret==0) // Both are the same type
1.150 + {
1.151 + ret=(-1); // left before right by default
1.152 + switch (cmpType)
1.153 + {
1.154 + case ESortNone:
1.155 + ret=1;
1.156 + break;
1.157 + case ESortByDate:
1.158 + if (left.Modified()>right.Modified())
1.159 + ret=1;
1.160 + else if (left.Modified()==right.Modified())
1.161 + ret=0;
1.162 + break;
1.163 + case ESortBySize:
1.164 +#ifndef SYMBIAN_ENABLE_64_BIT_FILE_SERVER_API
1.165 + if (I64LOW(left.Size()) > I64LOW(right.Size()))
1.166 + ret=1;
1.167 + else if (I64LOW(left.Size())==I64LOW(right.Size()))
1.168 + ret=0;
1.169 +#else
1.170 + if (left.Size() > right.Size())
1.171 + ret=1;
1.172 + else if (left.Size()==right.Size())
1.173 + ret=0;
1.174 +#endif
1.175 + break;
1.176 + case ESortByExt:
1.177 + {
1.178 + TInt i1 = KErrNotFound, i2 = KErrNotFound;
1.179 + if (left.Name() != _L(".") && left.Name() != _L(".."))
1.180 + i1 = left.Name().LocateReverse('.');
1.181 + if (right.Name() != _L(".") && right.Name() != _L(".."))
1.182 + i2 = right.Name().LocateReverse('.');
1.183 + if (i1==KErrNotFound && i2!=KErrNotFound)
1.184 + ret=(-1);
1.185 + else if (i2==KErrNotFound && i1!=KErrNotFound)
1.186 + ret=1;
1.187 + else if ((i1==KErrNotFound && i2==KErrNotFound) || (ret=left.Name().Mid(i1).CompareC(right.Name().Mid(i2)))==0)
1.188 + goto byName;
1.189 + }
1.190 + break;
1.191 + case ESortByUid:
1.192 + if (left.Type()[1]==right.Type()[1])
1.193 + {
1.194 + if (left.Type()[2]==right.Type()[2])
1.195 + ret = CompareByName(left, right);
1.196 + else if (left.Type()[2].iUid>right.Type()[2].iUid)
1.197 + ret=1;
1.198 + }
1.199 + else if (left.Type()[1].iUid==0)
1.200 + ret=1;
1.201 + else if (right.Type()[1].iUid==0)
1.202 + ret=-1;
1.203 + else if (left.Type()[1].iUid>right.Type()[1].iUid)
1.204 + ret=1;
1.205 + break;
1.206 + case ESortByName:
1.207 +byName:
1.208 + // Force the maximum collation level here (i.e. 3) for sorting strings
1.209 + ret = CompareByName(left, right);
1.210 + break;
1.211 + default: // Default is bad news
1.212 + Panic(ECDirBadSortType);
1.213 + }
1.214 + }
1.215 + if ((keyLength&EDescending)==EDescending)
1.216 + ret=(-ret); // Descending sort order
1.217 + return(ret);
1.218 + }
1.219 +
1.220 +TInt TKeyDir::CompareByName(TEntry2& aLeft, TEntry2& aRight) const
1.221 +//
1.222 +// Compare using collation key of entire name
1.223 +//
1.224 + {
1.225 + TInt ret = -1;
1.226 + TInt r = KErrNone;
1.227 +
1.228 + // Allocate partial key first and handle potential error case
1.229 + // by calling old CompareC
1.230 + // Note: only compare on the first collation level (KCollationLevel0) for partial keys,
1.231 + // to avoid potential inconsistency between full key and partial key comparison.
1.232 + if (!aLeft.iPartKey)
1.233 + {
1.234 + TRAP(r, aLeft.iPartKey = aLeft.Name().Left(KPartKeyLength).GetCollationKeysL(KCollationLevel0, &iCollationMethod));
1.235 + if (r != KErrNone)
1.236 + aLeft.iPartKey = KCollationKeyAllocFail;
1.237 + }
1.238 + if (!aRight.iPartKey)
1.239 + {
1.240 + TRAP(r, aRight.iPartKey = aRight.Name().Left(KPartKeyLength).GetCollationKeysL(KCollationLevel0, &iCollationMethod));
1.241 + if (r != KErrNone)
1.242 + aRight.iPartKey = KCollationKeyAllocFail;
1.243 + }
1.244 + if (aLeft.iPartKey == KCollationKeyAllocFail || aRight.iPartKey == KCollationKeyAllocFail)
1.245 + return aLeft.Name().CompareC(aRight.Name());
1.246 +
1.247 + // Compare by partial key first
1.248 + ret = aLeft.iPartKey->Compare(*aRight.iPartKey);
1.249 + if (ret != 0)
1.250 + return ret;
1.251 +
1.252 + // Compare by full key if partial keys are identical
1.253 + if (!aLeft.iFullKey)
1.254 + {
1.255 + TRAP(r, aLeft.iFullKey = aLeft.Name().GetCollationKeysL(KCollationLevelMax, &iCollationMethod));
1.256 + if (r != KErrNone)
1.257 + aLeft.iFullKey = KCollationKeyAllocFail;
1.258 + }
1.259 + if (!aRight.iFullKey)
1.260 + {
1.261 + TRAP(r, aRight.iFullKey = aRight.Name().GetCollationKeysL(KCollationLevelMax, &iCollationMethod));
1.262 + if (r != KErrNone)
1.263 + aRight.iFullKey = KCollationKeyAllocFail;
1.264 + }
1.265 + if (aLeft.iFullKey == KCollationKeyAllocFail || aRight.iFullKey == KCollationKeyAllocFail)
1.266 + // Using old CompareC if partial key allocation failed
1.267 + return aLeft.Name().CompareC(aRight.Name());
1.268 +
1.269 + // Compare using collation key of full names
1.270 + ret = aLeft.iFullKey->Compare(*aRight.iFullKey);
1.271 +
1.272 + return ret;
1.273 + }
1.274 +
1.275 +
1.276 +
1.277 +EXPORT_C CDir::CDir()
1.278 +/**
1.279 +Default constructor.
1.280 +*/
1.281 + {
1.282 + }
1.283 +
1.284 +
1.285 +
1.286 +
1.287 +EXPORT_C CDir::~CDir()
1.288 +/**
1.289 +Destructor.
1.290 +
1.291 +Frees all resources owned by the object, prior to its destruction.
1.292 +*/
1.293 + {
1.294 +
1.295 + delete iArray;
1.296 + }
1.297 +
1.298 +
1.299 +
1.300 +
1.301 +EXPORT_C CDir* CDir::NewL()
1.302 +/**
1.303 +Allocates and constructs a directory object.
1.304 +
1.305 +This function is protected, which prevents objects of this class from being
1.306 +directly constructed.
1.307 +
1.308 +@return A pointer to the newly created object.
1.309 +*/
1.310 + {
1.311 +
1.312 + CDir* pD=new(ELeave) CDir;
1.313 + pD->iArray=new CArrayPakFlat<TEntry>(KCDirArrayGranularity);
1.314 + if (pD->iArray==NULL)
1.315 + {
1.316 + delete pD;
1.317 + User::LeaveNoMemory();
1.318 + }
1.319 + return(pD);
1.320 + }
1.321 +
1.322 +
1.323 +
1.324 +
1.325 +EXPORT_C TInt CDir::Count() const
1.326 +/**
1.327 +Gets the number of entries in the array of directory
1.328 +entries.
1.329 +
1.330 +@return The number of entries in the array.
1.331 +*/
1.332 + {
1.333 +
1.334 + return(iArray->Count());
1.335 + }
1.336 +
1.337 +
1.338 +
1.339 +
1.340 +EXPORT_C const TEntry& CDir::operator[](TInt anIndex) const
1.341 +/**
1.342 +Gets an entry from the array of directory
1.343 +entries.
1.344 +
1.345 +@param anIndex of the desired entry within the array.
1.346 +
1.347 +@return A directory entry.
1.348 +*/
1.349 + {
1.350 +
1.351 + return((*iArray)[anIndex]);
1.352 + }
1.353 +
1.354 +
1.355 +/**
1.356 + * Utility class to manage dynamic array memory
1.357 + * @internalComponent
1.358 + */
1.359 +NONSHARABLE_CLASS(CAutoArray) : public CBase
1.360 + {
1.361 +public:
1.362 + ~CAutoArray();
1.363 +public:
1.364 + CArrayVarFlat<TEntry2>* iArray;
1.365 + };
1.366 +
1.367 +// Have to do this trick because CArrayVarFlat won't destroy element one by one
1.368 +CAutoArray::~CAutoArray()
1.369 + {
1.370 + if (iArray)
1.371 + for (TInt i=0; i<iArray->Count(); ++i)
1.372 + {
1.373 + TEntry2& e = (*iArray)[i];
1.374 + if (e.iPartKey != KCollationKeyAllocFail)
1.375 + delete e.iPartKey;
1.376 + if (e.iFullKey != KCollationKeyAllocFail)
1.377 + delete e.iFullKey;
1.378 + e.iPartKey = e.iFullKey = 0;
1.379 + }
1.380 + delete iArray;
1.381 + }
1.382 +
1.383 +EXPORT_C TInt CDir::Sort(TUint aKey)
1.384 +/**
1.385 +Sorts the array of directory entries.
1.386 +
1.387 +@param aKey A set of flags describing how the directory entries are to be sorted.
1.388 + The set of flags is defined by TEntryKey.
1.389 +
1.390 +@return KErrNone, if successful, otherwise one of the other system-wide error
1.391 + codes.
1.392 +
1.393 +@see TEntryKey
1.394 +*/
1.395 + {
1.396 + CAutoArray autoArray;
1.397 + #define array autoArray.iArray
1.398 +
1.399 + // Create TEntry2 array from iArray.
1.400 + array = new CArrayVarFlat<TEntry2>(KCDirArrayGranularity);
1.401 + if (!array)
1.402 + return KErrNoMemory;
1.403 +
1.404 + TInt arrayCount = iArray->Count();
1.405 + if (arrayCount == 0)
1.406 + return KErrNone;
1.407 +
1.408 + TEntry2* entry2 = new TEntry2((*iArray)[0]);
1.409 +
1.410 + if (!entry2)
1.411 + return KErrNoMemory;
1.412 +
1.413 + TInt i, r;
1.414 + for (i=0; i<arrayCount; ++i)
1.415 + {
1.416 + entry2->iEntry = (*iArray)[i];
1.417 + // Pack here
1.418 + TUint32* pSizeHighSrc = PtrAdd((TUint32*)&(entry2->iEntry), sizeof(TEntry) - 2 * sizeof(TInt));
1.419 + TUint32* pSizeHighDst = PtrAdd((TUint32*)&(entry2->iEntry), EntrySize(entry2->iEntry, EFalse));
1.420 +
1.421 + *pSizeHighDst++ = *pSizeHighSrc++; // Pack iSizeHigh
1.422 + *pSizeHighDst = *pSizeHighSrc; // Pack iReserved
1.423 + entry2->iEntry.iAtt |= KEntryAttPacked;
1.424 +
1.425 + TRAP(r, array->AppendL(*entry2, Entry2Size(*entry2)));
1.426 +
1.427 + if (r != KErrNone)
1.428 + {
1.429 + delete entry2;
1.430 + return r;
1.431 + }
1.432 + }
1.433 +
1.434 + // Sort new array
1.435 + TKeyDir key(aKey);
1.436 + r = array->Sort(key);
1.437 + if (r != KErrNone)
1.438 + {
1.439 + delete entry2;
1.440 + return r;
1.441 + }
1.442 +
1.443 + // Copy sorted result back to iArray
1.444 + iArray->Reset();
1.445 +
1.446 + for (i=0; i<array->Count(); ++i)
1.447 + {
1.448 + entry2->iEntry = (*array)[i].iEntry;
1.449 + // Pack here
1.450 + TUint32* pSizeHighSrc = PtrAdd((TUint32*)&(entry2->iEntry), sizeof(TEntry) - 2 * sizeof(TInt));
1.451 + TUint32* pSizeHighDst = PtrAdd((TUint32*)&(entry2->iEntry), EntrySize(entry2->iEntry, EFalse));
1.452 +
1.453 + *pSizeHighDst++ = *pSizeHighSrc++; // Pack iSizeHigh
1.454 + *pSizeHighDst = *pSizeHighSrc; // Pack iReserved
1.455 + entry2->iEntry.iAtt |= KEntryAttPacked;
1.456 +
1.457 + TRAP(r, iArray->AppendL(entry2->iEntry, EntrySize(entry2->iEntry, ETrue)));
1.458 + if (r != KErrNone)
1.459 + {
1.460 + delete entry2;
1.461 + return r;
1.462 + }
1.463 + }
1.464 +
1.465 + delete entry2;
1.466 + return r;
1.467 + }
1.468 +
1.469 +
1.470 +EXPORT_C void CDir::AddL(const TEntry& aEntry)
1.471 +/**
1.472 +Adds the specified entry to the directory.
1.473 +
1.474 +Note that the function can leave.
1.475 +
1.476 +@param aEntry The directory entry to be added.
1.477 +*/
1.478 + {
1.479 + if(aEntry.iAtt & KEntryAttPacked)
1.480 + {
1.481 + iArray->AppendL(aEntry,EntrySize(aEntry, ETrue));
1.482 + }
1.483 + else
1.484 + {
1.485 + TEntry entry = aEntry;
1.486 + // Pack here
1.487 + TUint32* pSizeHighSrc = PtrAdd((TUint32*)&entry, sizeof(TEntry) - 2 * sizeof(TInt));
1.488 + TUint32* pSizeHighDst = PtrAdd((TUint32*)&entry, EntrySize(entry, EFalse));
1.489 +
1.490 + *pSizeHighDst++ = *pSizeHighSrc++; // Pack iSizeHigh
1.491 + *pSizeHighDst = *pSizeHighSrc; // Pack iReserved
1.492 + entry.iAtt |= KEntryAttPacked;
1.493 + iArray->AppendL(entry,EntrySize(entry, ETrue));
1.494 + }
1.495 + }
1.496 +
1.497 +
1.498 +
1.499 +
1.500 +EXPORT_C void CDir::ExtractL(TBool aRemove,CDir* & aDir)
1.501 +/**
1.502 +Copies all directory entries from this directory array, and adds them to
1.503 +a new directory array.
1.504 +
1.505 +The directory entries in this array can be deleted.
1.506 +
1.507 +Note that the function can leave.
1.508 +
1.509 +@param aRemove If ETrue, the directory entries in this array are
1.510 + to be deleted after extraction;
1.511 + if EFalse, the directory entries are not to be deleted.
1.512 +
1.513 +@param aDir On return, a pointer to a CDir object containing
1.514 + the extracted directory entries.
1.515 +*/
1.516 + {
1.517 +
1.518 + aDir=NULL;
1.519 + aDir=CDir::NewL();
1.520 + CArrayPakFlat<TEntry>& anArray=(*iArray);
1.521 + TInt count=anArray.Count();
1.522 +
1.523 + if (count == 0)
1.524 + return;
1.525 +
1.526 + TInt i=0;
1.527 + while (i<count)
1.528 + {
1.529 + TEntry& e=anArray[i];
1.530 + if (e.IsDir())
1.531 + aDir->AddL(e);
1.532 + i++;
1.533 + }
1.534 + if (aRemove)
1.535 + {
1.536 + i=0;
1.537 + while (i<count)
1.538 + {
1.539 + if (anArray[i].IsDir())
1.540 + {
1.541 + anArray.Delete(i);
1.542 + count--;
1.543 + continue;
1.544 + }
1.545 + i++;
1.546 + }
1.547 + anArray.Compress();
1.548 + }
1.549 + aDir->Compress();
1.550 + }
1.551 +
1.552 +
1.553 +
1.554 +
1.555 +EXPORT_C void CDir::Compress()
1.556 +/**
1.557 +Compresses the directory.
1.558 +
1.559 +This has the effect of potentially reducing the ammount of storage
1.560 +space required on the media for that directory and the files it contains.
1.561 +Some files are already compressed and will not compress further.
1.562 +
1.563 +A potential side effect of compression is that each file is required to
1.564 +be uncompressed prior to use, generally increasing the time and
1.565 +processing cycles required to access that file.
1.566 +
1.567 +*/
1.568 + {
1.569 +
1.570 + iArray->Compress();
1.571 + }
1.572 +