|
1 /* |
|
2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 #include "CdlLibrary.h" |
|
18 #include "CCdlEngine.h" |
|
19 #include <e32svr.h> |
|
20 #include <f32file.h> |
|
21 #include <e32uid.h> |
|
22 #ifdef RD_SECURE_BIN_RES |
|
23 #include <ecom/ecom.h> |
|
24 #endif |
|
25 |
|
26 const TInt KCdlLibManGranularity = 4; |
|
27 const TUid KCdlLibraryUid = { 0x101F8BD1 }; |
|
28 |
|
29 template<class T> |
|
30 inline T* CheckPtrL(T* aPtr) |
|
31 { |
|
32 if (aPtr == NULL) |
|
33 User::Leave(KErrNotFound); |
|
34 return aPtr; |
|
35 } |
|
36 |
|
37 |
|
38 // |
|
39 // RCdlLibrary |
|
40 // |
|
41 |
|
42 enum TRCdlLibraryFlags |
|
43 { |
|
44 ERCdlLibrary_RomOnly |
|
45 }; |
|
46 |
|
47 RCdlLibrary::RCdlLibrary() : iName(0), iRefCount(0) |
|
48 ,iEcomDtorUid(KNullUid), iEcomImpl(0) |
|
49 { |
|
50 } |
|
51 |
|
52 void RCdlLibrary::Close() |
|
53 { |
|
54 REComSession::DestroyedImplementation(iEcomDtorUid); |
|
55 iEcomDtorUid.iUid = 0; |
|
56 iEcomImpl = 0; |
|
57 delete iName; |
|
58 iName = NULL; |
|
59 } |
|
60 |
|
61 TInt RCdlLibrary::CdlLoad(const TDesC& aLibName, TBool /*aRomOnly*/) |
|
62 { |
|
63 // get the ECom implementation id from the DLL name |
|
64 TParsePtrC parse(aLibName); |
|
65 TPtrC name(parse.Name()); |
|
66 TLex lexer(name); |
|
67 TUint32 uid; |
|
68 TInt r = lexer.Val(uid, EHex); |
|
69 if (r!=KErrNone) |
|
70 return r; |
|
71 |
|
72 TRAP(r, iEcomImpl = REComSession::CreateImplementationL(TUid::Uid(uid), iEcomDtorUid, NULL)); |
|
73 |
|
74 delete iName; |
|
75 iName = 0; |
|
76 |
|
77 if (r==KErrNone) |
|
78 { |
|
79 iName = aLibName.Alloc(); |
|
80 if (!iName) |
|
81 { |
|
82 Close(); |
|
83 return KErrNoMemory; |
|
84 } |
|
85 |
|
86 iShortName.Set(ExtractName(*iName)); |
|
87 } |
|
88 |
|
89 return r; |
|
90 } |
|
91 |
|
92 TBool RCdlLibrary::CheckIfNotRomOnly(TBool aRomOnly, const TDesC& aName) |
|
93 { |
|
94 return aRomOnly && |
|
95 aName.Length() >= 2 && aName[1] == ':' && |
|
96 aName[0] != 'z' && aName[0] != 'Z'; |
|
97 } |
|
98 |
|
99 const SCdlCustomisation* RCdlLibrary::CustomisationL(TUid aUid, TInt aImplId) const |
|
100 { |
|
101 const TCdlArray<SCdlCustomisation>& contents = ContentsL(); |
|
102 |
|
103 // first try the micro customisation optimisation, where aImplId is an index into |
|
104 // the contents table. |
|
105 if (0 <= aImplId && aImplId < contents.iCount) |
|
106 { |
|
107 const SCdlCustomisation& c = contents[aImplId]; |
|
108 if (c.iInterface->iUid == aUid && c.iId == aImplId) |
|
109 return &c; |
|
110 } |
|
111 |
|
112 // if that failed, scan the contents table. |
|
113 for (TInt ii=0; ii<contents.iCount; ii++) |
|
114 { |
|
115 const SCdlCustomisation& c = contents[ii]; |
|
116 if (c.iInterface->iUid == aUid && c.iId == aImplId) |
|
117 return &c; |
|
118 } |
|
119 |
|
120 User::Leave(KErrNotFound); |
|
121 return NULL; |
|
122 } |
|
123 |
|
124 const TCdlArray<SCdlCustomisation>& RCdlLibrary::ContentsL() const |
|
125 { |
|
126 TAny* f = iEcomImpl; |
|
127 SCdlMain* m = CheckPtrL((SCdlMain*)(f)); |
|
128 |
|
129 if (m->iMajorVer != KCdlCompilerMajorVersion || m->iMinorVer != KCdlCompilerMinorVersion) |
|
130 User::Leave(KErrCorrupt); |
|
131 return *CheckPtrL((const TCdlArray<SCdlCustomisation>*)(m->iData)); |
|
132 } |
|
133 |
|
134 TPtrC RCdlLibrary::Name() const |
|
135 { |
|
136 return iShortName; |
|
137 } |
|
138 |
|
139 const TDesC* RCdlLibrary::FullName() const |
|
140 { |
|
141 return iName; |
|
142 } |
|
143 |
|
144 TPtrC RCdlLibrary::ExtractName(const TDesC& aLibName) |
|
145 { |
|
146 // find the postion of the colon in aLibName |
|
147 TInt colonPos = aLibName.Locate(':'); |
|
148 // set name to be after the colon in aLibName, this works when colonPos is KErrNotFound (-1) too |
|
149 TPtrC name(aLibName.Mid(colonPos + 1)); |
|
150 // find the postion of the last slash |
|
151 TInt lastSlashPos = name.LocateReverse('\\'); |
|
152 // move name so that it only contains name after the last slash. Works with -1 again. |
|
153 name.Set(name.Mid(lastSlashPos + 1)); |
|
154 // find the position of the "." in the name |
|
155 TInt dotPos = name.Locate('.'); |
|
156 // if there is a dot, set the name to be the portion before the dot. |
|
157 if (dotPos != KErrNotFound) |
|
158 name.Set(name.Left(dotPos)); |
|
159 // name will now be the file name only, without extension. |
|
160 return name; |
|
161 } |
|
162 |
|
163 TBool RCdlLibrary::SameShortName(const TDesC& aShortLibName) |
|
164 { |
|
165 // Call Compare first, because it's much faster if the |
|
166 // strings match |
|
167 if (iShortName.Compare(aShortLibName) == 0) |
|
168 { |
|
169 return ETrue; |
|
170 } |
|
171 return iShortName.CompareF(aShortLibName) == 0; |
|
172 } |
|
173 |
|
174 TBool RCdlLibrary::IsLibLoadedAsRomOnly() const |
|
175 { |
|
176 return iFlags[ERCdlLibrary_RomOnly]; |
|
177 } |
|
178 |
|
179 void RCdlLibrary::SetLibLoadedAsRomOnly() |
|
180 { |
|
181 iFlags.Set(ERCdlLibrary_RomOnly); |
|
182 } |
|
183 |
|
184 // |
|
185 // RCdlLibRef |
|
186 // |
|
187 |
|
188 RCdlLibRef::RCdlLibRef() : iLibMan(0), iLib(0) |
|
189 { |
|
190 } |
|
191 |
|
192 void RCdlLibRef::Close() |
|
193 { |
|
194 if (iLib && iLibMan) |
|
195 iLibMan->Close(iLib); |
|
196 iLibMan = 0; |
|
197 iLib = 0; |
|
198 } |
|
199 |
|
200 RCdlLibrary* RCdlLibRef::Lib() const |
|
201 { |
|
202 return iLib; |
|
203 } |
|
204 |
|
205 void RCdlLibRef::SetRef(CCdlLibManager* aLibMan, RCdlLibrary* aLib) |
|
206 { |
|
207 __ASSERT_ALWAYS(!iLib && !iLibMan, Panic(ECdlEngPanic_LibraryAlreadySet)); |
|
208 iLibMan = aLibMan; |
|
209 iLib = aLib; |
|
210 } |
|
211 |
|
212 TPtrC RCdlLibRef::Name() const |
|
213 { |
|
214 return iLib->Name(); |
|
215 } |
|
216 |
|
217 |
|
218 |
|
219 // |
|
220 // CCdlLibManager |
|
221 // |
|
222 |
|
223 CCdlLibManager::CCdlLibManager() : iLibs(KCdlLibManGranularity) |
|
224 { |
|
225 } |
|
226 |
|
227 CCdlLibManager::~CCdlLibManager() |
|
228 { |
|
229 delete iLazyUnloader; |
|
230 TInt count = iLibs.Count(); |
|
231 for (TInt ii=0; ii<count; ii++) |
|
232 iLibs[ii]->Close(); |
|
233 iLibs.ResetAndDestroy(); |
|
234 if (iEcom) |
|
235 { |
|
236 iEcom->Close(); |
|
237 REComSession::FinalClose(); |
|
238 } |
|
239 } |
|
240 |
|
241 void CCdlLibManager::ConstructL() |
|
242 { |
|
243 iEcom = &REComSession::OpenL(); |
|
244 } |
|
245 |
|
246 RCdlLibRef CCdlLibManager::LoadL(const TDesC& aLibName, RCdlLibrary* aLib, TBool aRomOnly) |
|
247 { |
|
248 __ASSERT_DEBUG(aLib || !FindLib(aLibName), Panic(ECdlEngPanic_LibraryCanBeFound)); |
|
249 |
|
250 // load new library if a lib is not supplied |
|
251 if (!aLib) |
|
252 { |
|
253 aLib = new(ELeave) RCdlLibrary; |
|
254 CleanupStack::PushL(aLib); |
|
255 User::LeaveIfError(aLib->CdlLoad(aLibName, aRomOnly)); |
|
256 CleanupClosePushL(*aLib); |
|
257 iLibs.AppendL(aLib); |
|
258 CleanupStack::Pop(2); // lib->Close() and lib's heap cell |
|
259 } |
|
260 |
|
261 if (aRomOnly) |
|
262 { |
|
263 // the lib must be ROM only if aRomOnly is set and we got here. |
|
264 aLib->SetLibLoadedAsRomOnly(); |
|
265 } |
|
266 |
|
267 RCdlLibRef ref; |
|
268 ref.SetRef(this, aLib); |
|
269 aLib->RefCount()++; |
|
270 return ref; |
|
271 } |
|
272 |
|
273 void CCdlLibManager::Close(RCdlLibrary* aLib) |
|
274 { |
|
275 aLib->RefCount()--; |
|
276 if (aLib->RefCount()==0 && !iLazyUnloader) |
|
277 { |
|
278 // note, not (ELeave) because Close can't leave and |
|
279 // unloading can always be left till another time if |
|
280 // it doesn't work now. |
|
281 iLazyUnloader = new CAsyncCallBack(TCallBack(LazyUnload, this), CActive::EPriorityLow); |
|
282 if (iLazyUnloader) |
|
283 iLazyUnloader->CallBack(); |
|
284 } |
|
285 } |
|
286 |
|
287 TInt CCdlLibManager::LazyUnload(TAny* aThis) |
|
288 { |
|
289 static_cast<CCdlLibManager*>(aThis)->DoLazyUnload(); |
|
290 return 0; |
|
291 } |
|
292 |
|
293 void CCdlLibManager::DoLazyUnload() |
|
294 { |
|
295 TInt count = iLibs.Count(); |
|
296 for (TInt ii=count-1; ii>=0; ii--) |
|
297 { |
|
298 RCdlLibrary* lib = iLibs[ii]; |
|
299 if (lib->RefCount() <= 0) |
|
300 { |
|
301 iLibs.Delete(ii--); |
|
302 lib->Close(); |
|
303 delete lib; |
|
304 } |
|
305 } |
|
306 |
|
307 delete iLazyUnloader; |
|
308 iLazyUnloader = 0; |
|
309 } |
|
310 |
|
311 RCdlLibrary* CCdlLibManager::FindLib(const TDesC& aLibName) const |
|
312 { |
|
313 RCdlLibrary* lib = NULL; |
|
314 TPtrC libName(RCdlLibrary::ExtractName(aLibName)); |
|
315 |
|
316 // search for already loaded library |
|
317 TInt count = iLibs.Count(); |
|
318 for (TInt ii=0; ii<count; ii++) |
|
319 { |
|
320 if (iLibs[ii]->SameShortName(libName)) |
|
321 { |
|
322 lib = iLibs[ii]; |
|
323 break; |
|
324 } |
|
325 } |
|
326 |
|
327 return lib; |
|
328 } |
|
329 |
|
330 TBool CCdlLibManager::IsLibLoadedAsRomOnly(const TDesC& aLibName) const |
|
331 { |
|
332 RCdlLibrary* lib = FindLib(aLibName); |
|
333 return lib && lib->IsLibLoadedAsRomOnly(); |
|
334 } |