lowlevellibsandfws/apputils/src/BaSsndStore.cpp
changeset 0 e4d67989cc36
--- /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);
+		}
+	}