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 + }