--- /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 <s32mem.h>
+#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<TBaSystemSoundUid> ssuid(aSoundType.iMajor);
+ User::LeaveIfError(iRepository->Create(key++, ssuid));
+
+ TPckg<TBaSystemSoundType> 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<TBaSystemSoundInfo>& 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<TBaSystemSoundInfo>& aArray) const
+ {
+ RArray<TUint32> 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<TBaSystemSoundType> target(soundTypeCopy);
+ RArray<TUint32> 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<TUint32>& aKeys) const
+ {
+ TBaSystemSoundUid ssuidCopy = aSSUid;
+ TPckg<TBaSystemSoundUid> 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<TUint32> 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);
+ }
+ }