diff -r 000000000000 -r e4d67989cc36 lowlevellibsandfws/apputils/src/BaSsndStore.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lowlevellibsandfws/apputils/src/BaSsndStore.cpp Tue Feb 02 02:01:42 2010 +0200 @@ -0,0 +1,319 @@ +// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "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: +// + +/** + @file + @internalTechnology +*/ +#include +#include "BaSsndStore.h" +#include "BASSNDUID.h" + +// The repository format is: one setting for MajorUID, one +// setting for sound type, one setting for the actual sound +// data, and then leave one key space empty to round up to +// power of 2. +const TUint32 KSoundCatPartialKey = 0x1; +const TUint32 KSoundTypePartialKey = 0x2; +const TUint32 KSoundSettingPartialKey = 0x3; +const TUint32 KNumUnusedKeySpace = 1; +const TUint32 KSsndKeyMask = 0x3; + +const TUint32 KKeyOffsetFromSoundType = + KSoundSettingPartialKey - KSoundTypePartialKey; +const TUint32 KKeyOffsetFromSoundCat = + KSoundSettingPartialKey - KSoundCatPartialKey; +const TUint32 KSsndBlockSize = KSoundSettingPartialKey + KNumUnusedKeySpace; + +/** static factory method to instantiate an instance of CBaSsndStore */ +CBaSsndStore* CBaSsndStore::NewL() + { + CBaSsndStore* self = new(ELeave)CBaSsndStore; + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(); + return self; + } + +/** CBaSsndStore constructor */ +CBaSsndStore::CBaSsndStore() + { + } + +/** standard two phase construction to setup the CBaSsndStore object */ +void CBaSsndStore::ConstructL() + { + iRepository = CRepository::NewL(KSystemSoundRepositoryUID); + } + +/** CBaSsndStore destructor */ +CBaSsndStore::~CBaSsndStore() + { + delete iRepository; + } + +/** Retrieve sound data from repository. +@param aSoundType identifies the sound to retrieve. +@param aInfo contains the sound data on return. +@leave any of the system-wide error codes. +*/ +void CBaSsndStore::GetSoundL(const TBaSystemSoundType& aSoundType, + TBaSystemSoundInfo& aInfo) const + { + TUint32 key; + FindKeyL(aSoundType, key, EFalse); + + HBufC8* hbuf8 = HBufC8::NewLC(sizeof(TBaSystemSoundInfo)); + TPtr8 buf8 = hbuf8->Des(); + User::LeaveIfError(iRepository->Get(key + KKeyOffsetFromSoundType, buf8)); + + RDesReadStream strm(buf8); + aInfo.InternalizeL(strm); + + CleanupStack::PopAndDestroy(hbuf8); + + if (! (aSoundType == aInfo.iType)) + { + User::Leave(KErrCorrupt); + } + } + +/** Search for a sound from storage and return the sound data. +@param aInfo as input contains the ID of the sound instance to + get. As output, return the sound info if operation successful. +@return KErrNone if successful, otherwise KErrNotFound or + any other system-wide errors. +*/ +TInt CBaSsndStore::GetSound(const TBaSystemSoundType& aSoundType, + TBaSystemSoundInfo& aInfo) const + { + TRAPD(err, GetSoundL(aSoundType, aInfo)); + return err; + } + +/** +Overwrite existing sound if it is already in sound table. +Add it if it does not exist. +@param aInfo the sound data to save in repository. +@leave one of the system-wide errors if set fails. +*/ +void CBaSsndStore::SetSoundL(const TBaSystemSoundInfo& aInfo) const + { + HBufC8* hbuf8 = HBufC8::NewLC(sizeof(TBaSystemSoundInfo)); + TPtr8 buf8 = hbuf8->Des(); + RDesWriteStream writeStream( buf8 ); + aInfo.ExternalizeL(writeStream); + writeStream.CommitL(); + + TBaSystemSoundType ssType(aInfo.iType); + // If two threads simultaneously add sound, one of them + // will fail. Hence retry. + const TInt KMaxRetryTransaction = 3; + TInt err(KErrLocked); + for (TInt i = 0; + (i < KMaxRetryTransaction) && (err == KErrLocked || err == KErrAbort); + i++) + { + TRAP(err, SetSoundInTransactionL(ssType, buf8)); + } + + CleanupStack::PopAndDestroy(hbuf8); + User::LeaveIfError(err); + } + +/** If the given sound type exists in repository it is over written. +If not exists, create a new entry. This modify/create logic must be +wrapped in a CentRep transaction. +@param aSoundType Use this unique indentifier to find + if the sound already exists in repository. If it exists + use Set. If not, use Create. +@param aDes8 contains the sound data streamed to a TDesC8 buffer. +@leave any of the system-wide errors. +*/ +void CBaSsndStore::SetSoundInTransactionL(TBaSystemSoundType& aSoundType, + const TDesC8& aDes8) const + { + User::LeaveIfError( iRepository->StartTransaction(CRepository::EConcurrentReadWriteTransaction) ); + iRepository->CleanupCancelTransactionPushL(); + + TUint32 errorId; + + TUint32 key; + KeyOfSoundTypeL(aSoundType, key); + + if (key != NCentralRepositoryConstants::KUnspecifiedKey) + { + User::LeaveIfError(iRepository->Set(key + KKeyOffsetFromSoundType, aDes8)); + User::LeaveIfError(iRepository->CommitTransaction(errorId)); + CleanupStack::Pop(); // transaction + return; + } + + FindNextEmptySlotL(key); + + TPckg ssuid(aSoundType.iMajor); + User::LeaveIfError(iRepository->Create(key++, ssuid)); + + TPckg sstype(aSoundType); + User::LeaveIfError(iRepository->Create(key++, sstype)); + + User::LeaveIfError(iRepository->Create(key, aDes8) ); + + User::LeaveIfError(iRepository->CommitTransaction(errorId)); + CleanupStack::Pop(); // transaction + } + +/** Get all instances of a sound category +@param aSSUid identifies the category to retrieve. +@param aArray output parameter to return the sound instances +@return KErrNone if successful, else one of the system-wide error codes +*/ +TInt CBaSsndStore::GetSoundCategory(const TBaSystemSoundUid& aSSUid, + CArrayFixFlat& aArray) const + { + TRAPD(ret, GetSoundCategoryL(aSSUid, aArray)); + return ret; + } + +/** Get all instances of a sound category. +@param aSSUid identifies the category to retrieve. +@param aArray output parameter to return the sound instances. +@leave any of the system-wide error codes. +*/ +void CBaSsndStore::GetSoundCategoryL(const TBaSystemSoundUid& aSSUid, + CArrayFixFlat& aArray) const + { + RArray keys; + FindKeyL(aSSUid, keys); + CleanupClosePushL(keys); + + HBufC8* hbuf8 = HBufC8::NewLC(sizeof(TBaSystemSoundInfo)); + TPtr8 buf8 = hbuf8->Des(); + TBaSystemSoundInfo* sound = new(ELeave) TBaSystemSoundInfo; + CleanupStack::PushL(sound); + + TInt n = keys.Count(); + for (TInt i = 0; i < n; i++) + { + User::LeaveIfError(iRepository->Get( + keys[i] + KKeyOffsetFromSoundCat, buf8)); + RDesReadStream strm(buf8); + sound->InternalizeL(strm); + aArray.AppendL(*sound); + } + + CleanupStack::PopAndDestroy(sound); + CleanupStack::PopAndDestroy(hbuf8); + CleanupStack::PopAndDestroy(&keys); + } + +/** +Search for a sound instance in repository. +@param aSoundType identifies the TBaSystemSoundType to search for. +@param aKey output parameter containing the key of the sound type. +@param aNoLeaveIfNotFound indicate whether this method should leave if + the sound type is not found. +@leave KErrNotFound if not found, plus other system-wide errors. +*/ +void CBaSsndStore::FindKeyL(const TBaSystemSoundType& aSoundType, + TUint32& aKey, + TBool aNoLeaveIfNotFound) const + { + aKey = NCentralRepositoryConstants::KUnspecifiedKey; + + TBaSystemSoundType soundTypeCopy = aSoundType; + TPckg target(soundTypeCopy); + RArray foundIds; + + TInt ret = iRepository->FindEqL(KSoundTypePartialKey, + KSsndKeyMask, target, foundIds); + if (ret == KErrNotFound && aNoLeaveIfNotFound) + { + return; + } + + User::LeaveIfError(ret); + aKey = foundIds[0]; + foundIds.Reset(); + } + +/** +Search for a sound category +@param aSSUid the sound category to search for. +@param aKeys output parameter containing keys having the sound category + as their values. +@leave KErrNotFound if not found, plus other system-wide errors. +*/ +void CBaSsndStore::FindKeyL(const TBaSystemSoundUid& aSSUid, RArray& aKeys) const + { + TBaSystemSoundUid ssuidCopy = aSSUid; + TPckg target(ssuidCopy); + + User::LeaveIfError( iRepository->FindEqL(KSoundCatPartialKey, + KSsndKeyMask, target, aKeys) ); + } + +/** Call FindKeyL with aNoLeaveIfNotFound parameter set to true. +Used in SetSound to intercept and save the key. +@param aSoundType is the sound type to search for. +@param aKey output parameter to hold the key of the sound type. +@see CBaSsndStore::FindKeyL +*/ +void CBaSsndStore::KeyOfSoundTypeL(TBaSystemSoundType& aSoundType, + TUint32& aKey) const + { + FindKeyL(aSoundType, aKey, ETrue); + } + +/** +Find the next unused key to append a new sound. +@param aKey on return contains the key to use to store + the next sound. +@leave any of the system-wide error codes. +*/ +void CBaSsndStore::FindNextEmptySlotL(TUint32& aKey) const + { + RArray foundIds; + + TInt ret = iRepository->FindL(KSoundSettingPartialKey, + KSsndKeyMask, foundIds); + if (ret == KErrNotFound) + { + // Empty repository. Start storing at key 1 + aKey = 1; + } + else if (ret == KErrNone) + { + // The array is sorted. The max key is the last one in array. + TInt n = foundIds.Count(); + TUint32 maxkey = foundIds[n-1]; + foundIds.Reset(); + + TUint32 expectedArraySize = maxkey / KSsndBlockSize + 1; + if (expectedArraySize > n) + { + // Rogue app bypassed BaSystemSound and added non-contiguous + // entries in repository. + User::Leave(KErrCorrupt); + } + + // next record to be stored at maxkey + 2 + aKey = maxkey + KNumUnusedKeySpace + 1; + } + else + { + User::Leave(ret); + } + }