os/ossrv/lowlevellibsandfws/apputils/src/BaSsndStore.cpp
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/ossrv/lowlevellibsandfws/apputils/src/BaSsndStore.cpp	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,319 @@
     1.4 +// Copyright (c) 2006-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 "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 +//
    1.18 +
    1.19 +/**
    1.20 + @file
    1.21 + @internalTechnology
    1.22 +*/
    1.23 +#include <s32mem.h>
    1.24 +#include "BaSsndStore.h"
    1.25 +#include "BASSNDUID.h"
    1.26 +
    1.27 +// The repository format is: one setting for MajorUID, one
    1.28 +// setting for sound type, one setting for the actual sound
    1.29 +// data, and then leave one key space empty to round up to
    1.30 +// power of 2.
    1.31 +const TUint32 KSoundCatPartialKey = 0x1;
    1.32 +const TUint32 KSoundTypePartialKey = 0x2;
    1.33 +const TUint32 KSoundSettingPartialKey = 0x3;
    1.34 +const TUint32 KNumUnusedKeySpace = 1;
    1.35 +const TUint32 KSsndKeyMask = 0x3;
    1.36 +
    1.37 +const TUint32 KKeyOffsetFromSoundType = 
    1.38 +	KSoundSettingPartialKey - KSoundTypePartialKey;
    1.39 +const TUint32 KKeyOffsetFromSoundCat = 
    1.40 +	KSoundSettingPartialKey - KSoundCatPartialKey;
    1.41 +const TUint32 KSsndBlockSize = KSoundSettingPartialKey + KNumUnusedKeySpace;
    1.42 +
    1.43 +/** static factory method to instantiate an instance of CBaSsndStore */
    1.44 +CBaSsndStore* CBaSsndStore::NewL()
    1.45 +	{
    1.46 +	CBaSsndStore* self = new(ELeave)CBaSsndStore;
    1.47 +	CleanupStack::PushL(self);
    1.48 +	self->ConstructL();
    1.49 +	CleanupStack::Pop();
    1.50 +	return self;
    1.51 +	}
    1.52 +
    1.53 +/** CBaSsndStore constructor */
    1.54 +CBaSsndStore::CBaSsndStore()
    1.55 +	{
    1.56 +	}
    1.57 +
    1.58 +/** standard two phase construction to setup the CBaSsndStore object */
    1.59 +void CBaSsndStore::ConstructL()
    1.60 +	{
    1.61 +	iRepository = CRepository::NewL(KSystemSoundRepositoryUID);
    1.62 +	}
    1.63 +
    1.64 +/** CBaSsndStore destructor */
    1.65 +CBaSsndStore::~CBaSsndStore()
    1.66 +	{
    1.67 +	delete iRepository;
    1.68 +	}
    1.69 +
    1.70 +/** Retrieve sound data from repository.
    1.71 +@param aSoundType identifies the sound to retrieve.
    1.72 +@param aInfo contains the sound data on return.
    1.73 +@leave any of the system-wide error codes.
    1.74 +*/
    1.75 +void CBaSsndStore::GetSoundL(const TBaSystemSoundType& aSoundType,
    1.76 +							 TBaSystemSoundInfo& aInfo) const
    1.77 +	{
    1.78 +	TUint32 key;
    1.79 +	FindKeyL(aSoundType, key, EFalse);
    1.80 +
    1.81 +	HBufC8* hbuf8 = HBufC8::NewLC(sizeof(TBaSystemSoundInfo));
    1.82 +	TPtr8 buf8 = hbuf8->Des();
    1.83 +	User::LeaveIfError(iRepository->Get(key + KKeyOffsetFromSoundType, buf8));
    1.84 +
    1.85 +	RDesReadStream strm(buf8);
    1.86 +	aInfo.InternalizeL(strm);
    1.87 +
    1.88 +	CleanupStack::PopAndDestroy(hbuf8);
    1.89 +
    1.90 +	if (! (aSoundType == aInfo.iType))
    1.91 +		{
    1.92 +		User::Leave(KErrCorrupt);
    1.93 +		}
    1.94 +	}
    1.95 +
    1.96 +/** Search for a sound from storage and return the sound data.
    1.97 +@param aInfo as input contains the ID of the sound instance to
    1.98 +	get. As output, return the sound info if operation successful. 
    1.99 +@return KErrNone if successful, otherwise KErrNotFound or
   1.100 +	any other system-wide errors.
   1.101 +*/
   1.102 +TInt CBaSsndStore::GetSound(const TBaSystemSoundType& aSoundType,
   1.103 +							TBaSystemSoundInfo& aInfo) const
   1.104 +	{
   1.105 +	TRAPD(err, GetSoundL(aSoundType, aInfo));
   1.106 +	return err;
   1.107 +	}
   1.108 +
   1.109 +/**
   1.110 +Overwrite existing sound if it is already in sound table.
   1.111 +Add it if it does not exist.
   1.112 +@param aInfo the sound data to save in repository.
   1.113 +@leave one of the system-wide errors if set fails.
   1.114 +*/
   1.115 +void CBaSsndStore::SetSoundL(const TBaSystemSoundInfo& aInfo) const
   1.116 +	{
   1.117 +	HBufC8* hbuf8 = HBufC8::NewLC(sizeof(TBaSystemSoundInfo));
   1.118 +	TPtr8 buf8 = hbuf8->Des();
   1.119 +	RDesWriteStream writeStream( buf8 );
   1.120 +	aInfo.ExternalizeL(writeStream);
   1.121 +	writeStream.CommitL();
   1.122 +
   1.123 +	TBaSystemSoundType ssType(aInfo.iType);
   1.124 +	// If two threads simultaneously add sound, one of them
   1.125 +	// will fail. Hence retry.
   1.126 +	const TInt KMaxRetryTransaction = 3;
   1.127 +	TInt err(KErrLocked);
   1.128 +	for (TInt i = 0; 
   1.129 +		 (i < KMaxRetryTransaction) && (err == KErrLocked || err == KErrAbort);
   1.130 +		 i++)
   1.131 +		{
   1.132 +		TRAP(err, SetSoundInTransactionL(ssType, buf8));
   1.133 +		}
   1.134 +
   1.135 +	CleanupStack::PopAndDestroy(hbuf8);
   1.136 +	User::LeaveIfError(err);
   1.137 +	}
   1.138 +
   1.139 +/** If the given sound type exists in repository it is over written.
   1.140 +If not exists, create a new entry. This modify/create logic must be
   1.141 +wrapped in a CentRep transaction.
   1.142 +@param aSoundType Use this unique indentifier to find
   1.143 +       if the sound already exists in repository. If it exists
   1.144 +	   use Set. If not, use Create.
   1.145 +@param aDes8 contains the sound data streamed to a TDesC8 buffer.
   1.146 +@leave any of the system-wide errors.
   1.147 +*/
   1.148 +void CBaSsndStore::SetSoundInTransactionL(TBaSystemSoundType& aSoundType,
   1.149 +										  const TDesC8& aDes8) const
   1.150 +	{
   1.151 +	User::LeaveIfError( iRepository->StartTransaction(CRepository::EConcurrentReadWriteTransaction) );
   1.152 +	iRepository->CleanupCancelTransactionPushL();
   1.153 +
   1.154 +	TUint32 errorId;
   1.155 +
   1.156 +	TUint32 key;
   1.157 +	KeyOfSoundTypeL(aSoundType, key);
   1.158 +
   1.159 +	if (key != NCentralRepositoryConstants::KUnspecifiedKey)
   1.160 +		{
   1.161 +		User::LeaveIfError(iRepository->Set(key + KKeyOffsetFromSoundType, aDes8));
   1.162 +		User::LeaveIfError(iRepository->CommitTransaction(errorId));
   1.163 +		CleanupStack::Pop(); // transaction
   1.164 +		return;
   1.165 +		}
   1.166 +	
   1.167 +	FindNextEmptySlotL(key);
   1.168 +
   1.169 +	TPckg<TBaSystemSoundUid> ssuid(aSoundType.iMajor);
   1.170 +	User::LeaveIfError(iRepository->Create(key++, ssuid));
   1.171 +
   1.172 +	TPckg<TBaSystemSoundType> sstype(aSoundType);
   1.173 +	User::LeaveIfError(iRepository->Create(key++, sstype));
   1.174 +
   1.175 +	User::LeaveIfError(iRepository->Create(key, aDes8) );
   1.176 +
   1.177 +	User::LeaveIfError(iRepository->CommitTransaction(errorId));
   1.178 +	CleanupStack::Pop(); // transaction
   1.179 +	}
   1.180 +
   1.181 +/** Get all instances of a sound category
   1.182 +@param aSSUid identifies the category to retrieve.
   1.183 +@param aArray output parameter to return the sound instances
   1.184 +@return KErrNone if successful, else one of the system-wide error codes
   1.185 +*/
   1.186 +TInt CBaSsndStore::GetSoundCategory(const TBaSystemSoundUid& aSSUid,
   1.187 +									CArrayFixFlat<TBaSystemSoundInfo>& aArray) const
   1.188 +	{
   1.189 +	TRAPD(ret, GetSoundCategoryL(aSSUid, aArray));
   1.190 +	return ret;
   1.191 +	}
   1.192 +
   1.193 +/** Get all instances of a sound category.
   1.194 +@param aSSUid identifies the category to retrieve.
   1.195 +@param aArray output parameter to return the sound instances.
   1.196 +@leave any of the system-wide error codes.
   1.197 +*/
   1.198 +void CBaSsndStore::GetSoundCategoryL(const TBaSystemSoundUid& aSSUid,
   1.199 +									 CArrayFixFlat<TBaSystemSoundInfo>& aArray) const
   1.200 +	{
   1.201 +	RArray<TUint32> keys;
   1.202 +	FindKeyL(aSSUid, keys);
   1.203 +	CleanupClosePushL(keys);
   1.204 +
   1.205 +	HBufC8* hbuf8 = HBufC8::NewLC(sizeof(TBaSystemSoundInfo));
   1.206 +	TPtr8 buf8 = hbuf8->Des();
   1.207 +	TBaSystemSoundInfo* sound = new(ELeave) TBaSystemSoundInfo;
   1.208 +	CleanupStack::PushL(sound);
   1.209 +
   1.210 +	TInt n = keys.Count();
   1.211 +	for (TInt i = 0; i < n; i++)
   1.212 +		{
   1.213 +		User::LeaveIfError(iRepository->Get(
   1.214 +			keys[i] + KKeyOffsetFromSoundCat, buf8));
   1.215 +		RDesReadStream strm(buf8);
   1.216 +		sound->InternalizeL(strm);
   1.217 +		aArray.AppendL(*sound);
   1.218 +		}
   1.219 +
   1.220 +	CleanupStack::PopAndDestroy(sound);
   1.221 +	CleanupStack::PopAndDestroy(hbuf8);
   1.222 +	CleanupStack::PopAndDestroy(&keys);
   1.223 +	}
   1.224 +
   1.225 +/**
   1.226 +Search for a sound instance in repository.
   1.227 +@param aSoundType identifies the TBaSystemSoundType to search for.
   1.228 +@param aKey output parameter containing the key of the sound type.
   1.229 +@param aNoLeaveIfNotFound indicate whether this method should leave if
   1.230 +		the sound type is not found.
   1.231 +@leave KErrNotFound if not found, plus other system-wide errors.
   1.232 +*/
   1.233 +void CBaSsndStore::FindKeyL(const TBaSystemSoundType& aSoundType,
   1.234 +							TUint32& aKey,
   1.235 +							TBool aNoLeaveIfNotFound) const
   1.236 +	{
   1.237 +	aKey = NCentralRepositoryConstants::KUnspecifiedKey;
   1.238 +
   1.239 +	TBaSystemSoundType soundTypeCopy = aSoundType;
   1.240 +	TPckg<TBaSystemSoundType> target(soundTypeCopy);
   1.241 +	RArray<TUint32> foundIds;
   1.242 +
   1.243 +	TInt ret = iRepository->FindEqL(KSoundTypePartialKey, 
   1.244 +		KSsndKeyMask, target, foundIds);
   1.245 +	if (ret == KErrNotFound && aNoLeaveIfNotFound)
   1.246 +		{
   1.247 +		return;
   1.248 +		}
   1.249 +
   1.250 +	User::LeaveIfError(ret);
   1.251 +	aKey = foundIds[0];
   1.252 +	foundIds.Reset();
   1.253 +	}
   1.254 +
   1.255 +/**
   1.256 +Search for a sound category
   1.257 +@param aSSUid the sound category to search for.
   1.258 +@param aKeys output parameter containing keys having the sound category
   1.259 +		as their values.
   1.260 +@leave KErrNotFound if not found, plus other system-wide errors.
   1.261 +*/
   1.262 +void CBaSsndStore::FindKeyL(const TBaSystemSoundUid& aSSUid, RArray<TUint32>& aKeys) const
   1.263 +	{
   1.264 +	TBaSystemSoundUid ssuidCopy = aSSUid;
   1.265 +	TPckg<TBaSystemSoundUid> target(ssuidCopy);
   1.266 +
   1.267 +	User::LeaveIfError( iRepository->FindEqL(KSoundCatPartialKey, 
   1.268 +		KSsndKeyMask, target, aKeys) );
   1.269 +	}
   1.270 +
   1.271 +/** Call FindKeyL with aNoLeaveIfNotFound parameter set to true.
   1.272 +Used in SetSound to intercept and save the key.
   1.273 +@param aSoundType is the sound type to search for.
   1.274 +@param aKey output parameter to hold the key of the sound type.
   1.275 +@see CBaSsndStore::FindKeyL
   1.276 +*/
   1.277 +void CBaSsndStore::KeyOfSoundTypeL(TBaSystemSoundType& aSoundType,
   1.278 +								   TUint32& aKey) const
   1.279 +	{
   1.280 +	FindKeyL(aSoundType, aKey, ETrue);
   1.281 +	}
   1.282 +
   1.283 +/**
   1.284 +Find the next unused key to append a new sound.
   1.285 +@param aKey on return contains the key to use to store
   1.286 +	the next sound.
   1.287 +@leave any of the system-wide error codes.
   1.288 +*/
   1.289 +void CBaSsndStore::FindNextEmptySlotL(TUint32& aKey) const
   1.290 +	{
   1.291 +	RArray<TUint32> foundIds;
   1.292 +
   1.293 +	TInt ret = iRepository->FindL(KSoundSettingPartialKey,
   1.294 +		KSsndKeyMask, foundIds);
   1.295 +	if (ret == KErrNotFound)
   1.296 +		{
   1.297 +		// Empty repository. Start storing at key 1
   1.298 +		aKey = 1;
   1.299 +		}
   1.300 +	else if (ret == KErrNone)
   1.301 +		{
   1.302 +	    // The array is sorted. The max key is the last one in array.
   1.303 +		TInt n = foundIds.Count();
   1.304 +		TUint32 maxkey = foundIds[n-1];
   1.305 +		foundIds.Reset();
   1.306 +
   1.307 +		TUint32 expectedArraySize = maxkey / KSsndBlockSize + 1;
   1.308 +		if (expectedArraySize > n)
   1.309 +			{
   1.310 +			// Rogue app bypassed BaSystemSound and added non-contiguous
   1.311 +			// entries in repository.
   1.312 +			User::Leave(KErrCorrupt);
   1.313 +			}
   1.314 +
   1.315 +		// next record to be stored at maxkey + 2
   1.316 +		aKey = maxkey + KNumUnusedKeySpace + 1;
   1.317 +		}
   1.318 +	else
   1.319 +		{
   1.320 +		User::Leave(ret);
   1.321 +		}
   1.322 +	}