/*
* Copyright (c) 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:
*
*/
#include "CdlLibrary.h"
#include "CCdlEngine.h"
#include <e32svr.h>
#include <f32file.h>
#include <e32uid.h>
#ifdef RD_SECURE_BIN_RES
#include <ecom/ecom.h>
#endif
const TInt KCdlLibManGranularity = 4;
const TUid KCdlLibraryUid = { 0x101F8BD1 };
template<class T>
inline T* CheckPtrL(T* aPtr)
{
if (aPtr == NULL)
User::Leave(KErrNotFound);
return aPtr;
}
//
// RCdlLibrary
//
enum TRCdlLibraryFlags
{
ERCdlLibrary_RomOnly
};
RCdlLibrary::RCdlLibrary() : iName(0), iRefCount(0)
,iEcomDtorUid(KNullUid), iEcomImpl(0)
{
}
void RCdlLibrary::Close()
{
REComSession::DestroyedImplementation(iEcomDtorUid);
iEcomDtorUid.iUid = 0;
iEcomImpl = 0;
delete iName;
iName = NULL;
}
TInt RCdlLibrary::CdlLoad(const TDesC& aLibName, TBool /*aRomOnly*/)
{
// get the ECom implementation id from the DLL name
TParsePtrC parse(aLibName);
TPtrC name(parse.Name());
TLex lexer(name);
TUint32 uid;
TInt r = lexer.Val(uid, EHex);
if (r!=KErrNone)
return r;
TRAP(r, iEcomImpl = REComSession::CreateImplementationL(TUid::Uid(uid), iEcomDtorUid, NULL));
delete iName;
iName = 0;
if (r==KErrNone)
{
iName = aLibName.Alloc();
if (!iName)
{
Close();
return KErrNoMemory;
}
iShortName.Set(ExtractName(*iName));
}
return r;
}
TBool RCdlLibrary::CheckIfNotRomOnly(TBool aRomOnly, const TDesC& aName)
{
return aRomOnly &&
aName.Length() >= 2 && aName[1] == ':' &&
aName[0] != 'z' && aName[0] != 'Z';
}
const SCdlCustomisation* RCdlLibrary::CustomisationL(TUid aUid, TInt aImplId) const
{
const TCdlArray<SCdlCustomisation>& contents = ContentsL();
// first try the micro customisation optimisation, where aImplId is an index into
// the contents table.
if (0 <= aImplId && aImplId < contents.iCount)
{
const SCdlCustomisation& c = contents[aImplId];
if (c.iInterface->iUid == aUid && c.iId == aImplId)
return &c;
}
// if that failed, scan the contents table.
for (TInt ii=0; ii<contents.iCount; ii++)
{
const SCdlCustomisation& c = contents[ii];
if (c.iInterface->iUid == aUid && c.iId == aImplId)
return &c;
}
User::Leave(KErrNotFound);
return NULL;
}
const TCdlArray<SCdlCustomisation>& RCdlLibrary::ContentsL() const
{
TAny* f = iEcomImpl;
SCdlMain* m = CheckPtrL((SCdlMain*)(f));
if (m->iMajorVer != KCdlCompilerMajorVersion || m->iMinorVer != KCdlCompilerMinorVersion)
User::Leave(KErrCorrupt);
return *CheckPtrL((const TCdlArray<SCdlCustomisation>*)(m->iData));
}
TPtrC RCdlLibrary::Name() const
{
return iShortName;
}
const TDesC* RCdlLibrary::FullName() const
{
return iName;
}
TPtrC RCdlLibrary::ExtractName(const TDesC& aLibName)
{
// find the postion of the colon in aLibName
TInt colonPos = aLibName.Locate(':');
// set name to be after the colon in aLibName, this works when colonPos is KErrNotFound (-1) too
TPtrC name(aLibName.Mid(colonPos + 1));
// find the postion of the last slash
TInt lastSlashPos = name.LocateReverse('\\');
// move name so that it only contains name after the last slash. Works with -1 again.
name.Set(name.Mid(lastSlashPos + 1));
// find the position of the "." in the name
TInt dotPos = name.Locate('.');
// if there is a dot, set the name to be the portion before the dot.
if (dotPos != KErrNotFound)
name.Set(name.Left(dotPos));
// name will now be the file name only, without extension.
return name;
}
TBool RCdlLibrary::SameShortName(const TDesC& aShortLibName)
{
// Call Compare first, because it's much faster if the
// strings match
if (iShortName.Compare(aShortLibName) == 0)
{
return ETrue;
}
return iShortName.CompareF(aShortLibName) == 0;
}
TBool RCdlLibrary::IsLibLoadedAsRomOnly() const
{
return iFlags[ERCdlLibrary_RomOnly];
}
void RCdlLibrary::SetLibLoadedAsRomOnly()
{
iFlags.Set(ERCdlLibrary_RomOnly);
}
//
// RCdlLibRef
//
RCdlLibRef::RCdlLibRef() : iLibMan(0), iLib(0)
{
}
void RCdlLibRef::Close()
{
if (iLib && iLibMan)
iLibMan->Close(iLib);
iLibMan = 0;
iLib = 0;
}
RCdlLibrary* RCdlLibRef::Lib() const
{
return iLib;
}
void RCdlLibRef::SetRef(CCdlLibManager* aLibMan, RCdlLibrary* aLib)
{
__ASSERT_ALWAYS(!iLib && !iLibMan, Panic(ECdlEngPanic_LibraryAlreadySet));
iLibMan = aLibMan;
iLib = aLib;
}
TPtrC RCdlLibRef::Name() const
{
return iLib->Name();
}
//
// CCdlLibManager
//
CCdlLibManager::CCdlLibManager() : iLibs(KCdlLibManGranularity)
{
}
CCdlLibManager::~CCdlLibManager()
{
delete iLazyUnloader;
TInt count = iLibs.Count();
for (TInt ii=0; ii<count; ii++)
iLibs[ii]->Close();
iLibs.ResetAndDestroy();
if (iEcom)
{
iEcom->Close();
REComSession::FinalClose();
}
}
void CCdlLibManager::ConstructL()
{
iEcom = &REComSession::OpenL();
}
RCdlLibRef CCdlLibManager::LoadL(const TDesC& aLibName, RCdlLibrary* aLib, TBool aRomOnly)
{
__ASSERT_DEBUG(aLib || !FindLib(aLibName), Panic(ECdlEngPanic_LibraryCanBeFound));
// load new library if a lib is not supplied
if (!aLib)
{
aLib = new(ELeave) RCdlLibrary;
CleanupStack::PushL(aLib);
User::LeaveIfError(aLib->CdlLoad(aLibName, aRomOnly));
CleanupClosePushL(*aLib);
iLibs.AppendL(aLib);
CleanupStack::Pop(2); // lib->Close() and lib's heap cell
}
if (aRomOnly)
{
// the lib must be ROM only if aRomOnly is set and we got here.
aLib->SetLibLoadedAsRomOnly();
}
RCdlLibRef ref;
ref.SetRef(this, aLib);
aLib->RefCount()++;
return ref;
}
void CCdlLibManager::Close(RCdlLibrary* aLib)
{
aLib->RefCount()--;
if (aLib->RefCount()==0 && !iLazyUnloader)
{
// note, not (ELeave) because Close can't leave and
// unloading can always be left till another time if
// it doesn't work now.
iLazyUnloader = new CAsyncCallBack(TCallBack(LazyUnload, this), CActive::EPriorityLow);
if (iLazyUnloader)
iLazyUnloader->CallBack();
}
}
TInt CCdlLibManager::LazyUnload(TAny* aThis)
{
static_cast<CCdlLibManager*>(aThis)->DoLazyUnload();
return 0;
}
void CCdlLibManager::DoLazyUnload()
{
TInt count = iLibs.Count();
for (TInt ii=count-1; ii>=0; ii--)
{
RCdlLibrary* lib = iLibs[ii];
if (lib->RefCount() <= 0)
{
iLibs.Delete(ii--);
lib->Close();
delete lib;
}
}
delete iLazyUnloader;
iLazyUnloader = 0;
}
RCdlLibrary* CCdlLibManager::FindLib(const TDesC& aLibName) const
{
RCdlLibrary* lib = NULL;
TPtrC libName(RCdlLibrary::ExtractName(aLibName));
// search for already loaded library
TInt count = iLibs.Count();
for (TInt ii=0; ii<count; ii++)
{
if (iLibs[ii]->SameShortName(libName))
{
lib = iLibs[ii];
break;
}
}
return lib;
}
TBool CCdlLibManager::IsLibLoadedAsRomOnly(const TDesC& aLibName) const
{
RCdlLibrary* lib = FindLib(aLibName);
return lib && lib->IsLibLoadedAsRomOnly();
}