|
1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 /** |
|
17 @file |
|
18 @internalTechnology |
|
19 */ |
|
20 #include <s32mem.h> |
|
21 #include "BaSsndStore.h" |
|
22 #include "BASSNDUID.h" |
|
23 |
|
24 // The repository format is: one setting for MajorUID, one |
|
25 // setting for sound type, one setting for the actual sound |
|
26 // data, and then leave one key space empty to round up to |
|
27 // power of 2. |
|
28 const TUint32 KSoundCatPartialKey = 0x1; |
|
29 const TUint32 KSoundTypePartialKey = 0x2; |
|
30 const TUint32 KSoundSettingPartialKey = 0x3; |
|
31 const TUint32 KNumUnusedKeySpace = 1; |
|
32 const TUint32 KSsndKeyMask = 0x3; |
|
33 |
|
34 const TUint32 KKeyOffsetFromSoundType = |
|
35 KSoundSettingPartialKey - KSoundTypePartialKey; |
|
36 const TUint32 KKeyOffsetFromSoundCat = |
|
37 KSoundSettingPartialKey - KSoundCatPartialKey; |
|
38 const TUint32 KSsndBlockSize = KSoundSettingPartialKey + KNumUnusedKeySpace; |
|
39 |
|
40 /** static factory method to instantiate an instance of CBaSsndStore */ |
|
41 CBaSsndStore* CBaSsndStore::NewL() |
|
42 { |
|
43 CBaSsndStore* self = new(ELeave)CBaSsndStore; |
|
44 CleanupStack::PushL(self); |
|
45 self->ConstructL(); |
|
46 CleanupStack::Pop(); |
|
47 return self; |
|
48 } |
|
49 |
|
50 /** CBaSsndStore constructor */ |
|
51 CBaSsndStore::CBaSsndStore() |
|
52 { |
|
53 } |
|
54 |
|
55 /** standard two phase construction to setup the CBaSsndStore object */ |
|
56 void CBaSsndStore::ConstructL() |
|
57 { |
|
58 iRepository = CRepository::NewL(KSystemSoundRepositoryUID); |
|
59 } |
|
60 |
|
61 /** CBaSsndStore destructor */ |
|
62 CBaSsndStore::~CBaSsndStore() |
|
63 { |
|
64 delete iRepository; |
|
65 } |
|
66 |
|
67 /** Retrieve sound data from repository. |
|
68 @param aSoundType identifies the sound to retrieve. |
|
69 @param aInfo contains the sound data on return. |
|
70 @leave any of the system-wide error codes. |
|
71 */ |
|
72 void CBaSsndStore::GetSoundL(const TBaSystemSoundType& aSoundType, |
|
73 TBaSystemSoundInfo& aInfo) const |
|
74 { |
|
75 TUint32 key; |
|
76 FindKeyL(aSoundType, key, EFalse); |
|
77 |
|
78 HBufC8* hbuf8 = HBufC8::NewLC(sizeof(TBaSystemSoundInfo)); |
|
79 TPtr8 buf8 = hbuf8->Des(); |
|
80 User::LeaveIfError(iRepository->Get(key + KKeyOffsetFromSoundType, buf8)); |
|
81 |
|
82 RDesReadStream strm(buf8); |
|
83 aInfo.InternalizeL(strm); |
|
84 |
|
85 CleanupStack::PopAndDestroy(hbuf8); |
|
86 |
|
87 if (! (aSoundType == aInfo.iType)) |
|
88 { |
|
89 User::Leave(KErrCorrupt); |
|
90 } |
|
91 } |
|
92 |
|
93 /** Search for a sound from storage and return the sound data. |
|
94 @param aInfo as input contains the ID of the sound instance to |
|
95 get. As output, return the sound info if operation successful. |
|
96 @return KErrNone if successful, otherwise KErrNotFound or |
|
97 any other system-wide errors. |
|
98 */ |
|
99 TInt CBaSsndStore::GetSound(const TBaSystemSoundType& aSoundType, |
|
100 TBaSystemSoundInfo& aInfo) const |
|
101 { |
|
102 TRAPD(err, GetSoundL(aSoundType, aInfo)); |
|
103 return err; |
|
104 } |
|
105 |
|
106 /** |
|
107 Overwrite existing sound if it is already in sound table. |
|
108 Add it if it does not exist. |
|
109 @param aInfo the sound data to save in repository. |
|
110 @leave one of the system-wide errors if set fails. |
|
111 */ |
|
112 void CBaSsndStore::SetSoundL(const TBaSystemSoundInfo& aInfo) const |
|
113 { |
|
114 HBufC8* hbuf8 = HBufC8::NewLC(sizeof(TBaSystemSoundInfo)); |
|
115 TPtr8 buf8 = hbuf8->Des(); |
|
116 RDesWriteStream writeStream( buf8 ); |
|
117 aInfo.ExternalizeL(writeStream); |
|
118 writeStream.CommitL(); |
|
119 |
|
120 TBaSystemSoundType ssType(aInfo.iType); |
|
121 // If two threads simultaneously add sound, one of them |
|
122 // will fail. Hence retry. |
|
123 const TInt KMaxRetryTransaction = 3; |
|
124 TInt err(KErrLocked); |
|
125 for (TInt i = 0; |
|
126 (i < KMaxRetryTransaction) && (err == KErrLocked || err == KErrAbort); |
|
127 i++) |
|
128 { |
|
129 TRAP(err, SetSoundInTransactionL(ssType, buf8)); |
|
130 } |
|
131 |
|
132 CleanupStack::PopAndDestroy(hbuf8); |
|
133 User::LeaveIfError(err); |
|
134 } |
|
135 |
|
136 /** If the given sound type exists in repository it is over written. |
|
137 If not exists, create a new entry. This modify/create logic must be |
|
138 wrapped in a CentRep transaction. |
|
139 @param aSoundType Use this unique indentifier to find |
|
140 if the sound already exists in repository. If it exists |
|
141 use Set. If not, use Create. |
|
142 @param aDes8 contains the sound data streamed to a TDesC8 buffer. |
|
143 @leave any of the system-wide errors. |
|
144 */ |
|
145 void CBaSsndStore::SetSoundInTransactionL(TBaSystemSoundType& aSoundType, |
|
146 const TDesC8& aDes8) const |
|
147 { |
|
148 User::LeaveIfError( iRepository->StartTransaction(CRepository::EConcurrentReadWriteTransaction) ); |
|
149 iRepository->CleanupCancelTransactionPushL(); |
|
150 |
|
151 TUint32 errorId; |
|
152 |
|
153 TUint32 key; |
|
154 KeyOfSoundTypeL(aSoundType, key); |
|
155 |
|
156 if (key != NCentralRepositoryConstants::KUnspecifiedKey) |
|
157 { |
|
158 User::LeaveIfError(iRepository->Set(key + KKeyOffsetFromSoundType, aDes8)); |
|
159 User::LeaveIfError(iRepository->CommitTransaction(errorId)); |
|
160 CleanupStack::Pop(); // transaction |
|
161 return; |
|
162 } |
|
163 |
|
164 FindNextEmptySlotL(key); |
|
165 |
|
166 TPckg<TBaSystemSoundUid> ssuid(aSoundType.iMajor); |
|
167 User::LeaveIfError(iRepository->Create(key++, ssuid)); |
|
168 |
|
169 TPckg<TBaSystemSoundType> sstype(aSoundType); |
|
170 User::LeaveIfError(iRepository->Create(key++, sstype)); |
|
171 |
|
172 User::LeaveIfError(iRepository->Create(key, aDes8) ); |
|
173 |
|
174 User::LeaveIfError(iRepository->CommitTransaction(errorId)); |
|
175 CleanupStack::Pop(); // transaction |
|
176 } |
|
177 |
|
178 /** Get all instances of a sound category |
|
179 @param aSSUid identifies the category to retrieve. |
|
180 @param aArray output parameter to return the sound instances |
|
181 @return KErrNone if successful, else one of the system-wide error codes |
|
182 */ |
|
183 TInt CBaSsndStore::GetSoundCategory(const TBaSystemSoundUid& aSSUid, |
|
184 CArrayFixFlat<TBaSystemSoundInfo>& aArray) const |
|
185 { |
|
186 TRAPD(ret, GetSoundCategoryL(aSSUid, aArray)); |
|
187 return ret; |
|
188 } |
|
189 |
|
190 /** Get all instances of a sound category. |
|
191 @param aSSUid identifies the category to retrieve. |
|
192 @param aArray output parameter to return the sound instances. |
|
193 @leave any of the system-wide error codes. |
|
194 */ |
|
195 void CBaSsndStore::GetSoundCategoryL(const TBaSystemSoundUid& aSSUid, |
|
196 CArrayFixFlat<TBaSystemSoundInfo>& aArray) const |
|
197 { |
|
198 RArray<TUint32> keys; |
|
199 FindKeyL(aSSUid, keys); |
|
200 CleanupClosePushL(keys); |
|
201 |
|
202 HBufC8* hbuf8 = HBufC8::NewLC(sizeof(TBaSystemSoundInfo)); |
|
203 TPtr8 buf8 = hbuf8->Des(); |
|
204 TBaSystemSoundInfo* sound = new(ELeave) TBaSystemSoundInfo; |
|
205 CleanupStack::PushL(sound); |
|
206 |
|
207 TInt n = keys.Count(); |
|
208 for (TInt i = 0; i < n; i++) |
|
209 { |
|
210 User::LeaveIfError(iRepository->Get( |
|
211 keys[i] + KKeyOffsetFromSoundCat, buf8)); |
|
212 RDesReadStream strm(buf8); |
|
213 sound->InternalizeL(strm); |
|
214 aArray.AppendL(*sound); |
|
215 } |
|
216 |
|
217 CleanupStack::PopAndDestroy(sound); |
|
218 CleanupStack::PopAndDestroy(hbuf8); |
|
219 CleanupStack::PopAndDestroy(&keys); |
|
220 } |
|
221 |
|
222 /** |
|
223 Search for a sound instance in repository. |
|
224 @param aSoundType identifies the TBaSystemSoundType to search for. |
|
225 @param aKey output parameter containing the key of the sound type. |
|
226 @param aNoLeaveIfNotFound indicate whether this method should leave if |
|
227 the sound type is not found. |
|
228 @leave KErrNotFound if not found, plus other system-wide errors. |
|
229 */ |
|
230 void CBaSsndStore::FindKeyL(const TBaSystemSoundType& aSoundType, |
|
231 TUint32& aKey, |
|
232 TBool aNoLeaveIfNotFound) const |
|
233 { |
|
234 aKey = NCentralRepositoryConstants::KUnspecifiedKey; |
|
235 |
|
236 TBaSystemSoundType soundTypeCopy = aSoundType; |
|
237 TPckg<TBaSystemSoundType> target(soundTypeCopy); |
|
238 RArray<TUint32> foundIds; |
|
239 |
|
240 TInt ret = iRepository->FindEqL(KSoundTypePartialKey, |
|
241 KSsndKeyMask, target, foundIds); |
|
242 if (ret == KErrNotFound && aNoLeaveIfNotFound) |
|
243 { |
|
244 return; |
|
245 } |
|
246 |
|
247 User::LeaveIfError(ret); |
|
248 aKey = foundIds[0]; |
|
249 foundIds.Reset(); |
|
250 } |
|
251 |
|
252 /** |
|
253 Search for a sound category |
|
254 @param aSSUid the sound category to search for. |
|
255 @param aKeys output parameter containing keys having the sound category |
|
256 as their values. |
|
257 @leave KErrNotFound if not found, plus other system-wide errors. |
|
258 */ |
|
259 void CBaSsndStore::FindKeyL(const TBaSystemSoundUid& aSSUid, RArray<TUint32>& aKeys) const |
|
260 { |
|
261 TBaSystemSoundUid ssuidCopy = aSSUid; |
|
262 TPckg<TBaSystemSoundUid> target(ssuidCopy); |
|
263 |
|
264 User::LeaveIfError( iRepository->FindEqL(KSoundCatPartialKey, |
|
265 KSsndKeyMask, target, aKeys) ); |
|
266 } |
|
267 |
|
268 /** Call FindKeyL with aNoLeaveIfNotFound parameter set to true. |
|
269 Used in SetSound to intercept and save the key. |
|
270 @param aSoundType is the sound type to search for. |
|
271 @param aKey output parameter to hold the key of the sound type. |
|
272 @see CBaSsndStore::FindKeyL |
|
273 */ |
|
274 void CBaSsndStore::KeyOfSoundTypeL(TBaSystemSoundType& aSoundType, |
|
275 TUint32& aKey) const |
|
276 { |
|
277 FindKeyL(aSoundType, aKey, ETrue); |
|
278 } |
|
279 |
|
280 /** |
|
281 Find the next unused key to append a new sound. |
|
282 @param aKey on return contains the key to use to store |
|
283 the next sound. |
|
284 @leave any of the system-wide error codes. |
|
285 */ |
|
286 void CBaSsndStore::FindNextEmptySlotL(TUint32& aKey) const |
|
287 { |
|
288 RArray<TUint32> foundIds; |
|
289 |
|
290 TInt ret = iRepository->FindL(KSoundSettingPartialKey, |
|
291 KSsndKeyMask, foundIds); |
|
292 if (ret == KErrNotFound) |
|
293 { |
|
294 // Empty repository. Start storing at key 1 |
|
295 aKey = 1; |
|
296 } |
|
297 else if (ret == KErrNone) |
|
298 { |
|
299 // The array is sorted. The max key is the last one in array. |
|
300 TInt n = foundIds.Count(); |
|
301 TUint32 maxkey = foundIds[n-1]; |
|
302 foundIds.Reset(); |
|
303 |
|
304 TUint32 expectedArraySize = maxkey / KSsndBlockSize + 1; |
|
305 if (expectedArraySize > n) |
|
306 { |
|
307 // Rogue app bypassed BaSystemSound and added non-contiguous |
|
308 // entries in repository. |
|
309 User::Leave(KErrCorrupt); |
|
310 } |
|
311 |
|
312 // next record to be stored at maxkey + 2 |
|
313 aKey = maxkey + KNumUnusedKeySpace + 1; |
|
314 } |
|
315 else |
|
316 { |
|
317 User::Leave(ret); |
|
318 } |
|
319 } |