diff -r 000000000000 -r 05e9090e2422 layouts/cdl/CdlEngine/src/CdlCustomisation.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/layouts/cdl/CdlEngine/src/CdlCustomisation.cpp Thu Dec 17 09:14:12 2009 +0200 @@ -0,0 +1,452 @@ +/* +* 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 "CdlCustomisation.h" +#include "CCdlEngine.h" +#include + +const TInt KCustomisationStackGranularity = 2; + +const TUint32 KCdlInstanceFlagIsComplete = 0x1; + +// +// CCdlInstance +// + +EXPORT_C CCdlInstance* CCdlInstance::NewL(const TCdlRef& aRef, + const SCdlInterface* aInterfaceParams, + const CCdlInstance* aSubLayer, + CCdlEngine* aEngine, + TInt* aLastApi) + { + CCdlInstance* self = NewLC(aRef, aInterfaceParams, aSubLayer, aEngine, aLastApi); + CleanupStack::Pop(self); + return self; + } + +EXPORT_C CCdlInstance* CCdlInstance::NewLC(const TCdlRef& aRef, + const SCdlInterface* aInterfaceParams, + const CCdlInstance* aSubLayer, + CCdlEngine* aEngine, + TInt* aLastApi) + { + // get/create the CDL engine, if necessary + TBool pushed = EFalse; + if (!aEngine) + aEngine = CCdlEngine::InstanceLC(pushed); + // get the last API ref, if necessary + if (!aLastApi) + aLastApi = aEngine->LastApiRefL(aInterfaceParams->iUid); + // CCdlDllInstance is the only appropriate concrete implementation of CCdlInstance, so create one. + // Note, when other imlementation types become available, there will need to be a descision here about + // what implementation type is required + CCdlDllInstance* self = new(ELeave) CCdlDllInstance(aRef, aSubLayer, aEngine, aLastApi); + // engine will be owned by the instance if it was created + if (pushed) + CleanupStack::Pop(aEngine); + // finish construction. Again, this may depend on implementation type. + CleanupStack::PushL(self); + self->ConstructL(aInterfaceParams->iFlags & KCdlFlagRomOnly, aInterfaceParams->iApiSize); + return self; + } + +CCdlInstance::CCdlInstance(CCdlEngine* aEngine, TInt* aLastApi) +: CCdlEngineRef(aEngine), iLastApi(*aLastApi) + { + } + +EXPORT_C TAny* CCdlInstance::GetData(TInt aCdlApiId) const + { + iLastApi = aCdlApiId; + ((CCdlEngine*)Engine())->SetLastApiId(aCdlApiId); + return Implementor(aCdlApiId)->Implementation(aCdlApiId); + } + +EXPORT_C TCdlEngineFunc* CCdlInstance::GetFunction(TInt aCdlApiId) const + { + iLastApi = aCdlApiId; + ((CCdlEngine*)Engine())->SetLastApiId(aCdlApiId); + const CCdlInstance* inst = this; + TCdlEngineFunc* func = 0; + do + { + if (aCdlApiId < inst->Interface().iApiSize) + func = (TCdlEngineFunc*)(inst->Implementation(aCdlApiId)); + inst = inst->iSubLayer; + } while (!func && inst); + __ASSERT_ALWAYS(func, Panic(ECdlEngPanic_NoImplementation)); + return func; + } + +const CCdlInstance* CCdlInstance::Implementor(TInt aCdlApiId) const + { + if (aCdlApiId < Interface().iApiSize && Implementation(aCdlApiId)) + return this; + __ASSERT_ALWAYS(iSubLayer, Panic(ECdlEngPanic_NoImplementation)); + return iSubLayer->Implementor(aCdlApiId); + } + +EXPORT_C const TCdlRef& CCdlInstance::Ref() const + { + return iRef; + } + +EXPORT_C const CCdlInstance* CCdlInstance::SubLayer() const + { + return iSubLayer; + } + +EXPORT_C const TCdlRef& CCdlInstance::LastAccessedRef() const + { + return Implementor(iLastApi)->Ref(); + } + +EXPORT_C void CCdlInstance::FileNameRelativeToLastAccessedInstance(TFileName& aFileName) const + { + TParse parse; + parse.Set(aFileName, LastAccessedRef().iName, NULL); + aFileName = parse.FullName(); + } + +EXPORT_C TBool CCdlInstance::operator==(const CCdlInstance& aOther) const + { + return iRef.iId == aOther.iRef.iId && CdlEngine::CompareNames(*iRef.iName, *aOther.iRef.iName) == 0; + } + +TAny* CCdlInstance::Extension(TInt /*aId*/) const + { + return NULL; + } + + +// +// CCdlDllInstance +// + +CCdlDllInstance::CCdlDllInstance(const TCdlRef& aRef, const CCdlInstance* aSubLayer, CCdlEngine* aEngine, TInt* aLastApi) +: CCdlInstance(aEngine, aLastApi) + { + iRef = aRef; + iSubLayer = aSubLayer; + __ASSERT_ALWAYS(!iSubLayer || iSubLayer->Ref().iUid == aRef.iUid, Panic(ECdlEngPanic_IncompatibleSubLayer)); + } + +CCdlDllInstance::~CCdlDllInstance() + { + iLib.Close(); + } + +void CCdlDllInstance::ConstructL(TBool aRomOnly, TInt aApiSize) + { + CCdlLibManager* libMan = Engine()->LibMan(); + + + // get the filename pointer, so that it can have drive name added if necessary + const TDesC* name = iRef.iName; + TFileName tempName; + // first look if the library is already loaded + RCdlLibrary* lib = libMan->FindLib(*name); + if (lib) + { + // get the name from the library, it will be sure to have the drive letter present + name = lib->FullName(); + } + else + { + // library is not loaded + if ((*name)[1] != ':') // test if the filename is missing a drive letter + { + // get the drive for this plugin + TDriveUnit drive; + User::LeaveIfError(Engine()->PluginDrive(*name, drive)); + // build the new filename and set the pointer to it + tempName = drive.Name(); + tempName.Append(*name); + name = &tempName; + } + } + + // for CDL/ECom, test the ROM status before loading. .DLL loading + // tests ROM status during load. +#ifdef RD_SECURE_BIN_RES + if (RCdlLibrary::CheckIfNotRomOnly(aRomOnly, *name)) + { + User::Leave(KErrAccessDenied); + } +#endif + + // get the library + iLib = libMan->LoadL(*name, lib, aRomOnly); + lib = iLib.Lib(); + iRef.iName = lib->FullName(); + + // get the customisation data for this instance + const SCdlCustomisation* cust = lib->CustomisationL(iRef.iUid, iRef.iId); + + // get the table of pointers + iApi = (TAny**)(cust->iImpl); + + // get the interface + iInterface = cust->iInterface; + + // find out if this implementation is complete + SetIsCompleteFlag(aApiSize); + + // Check that instances with no sub-layer are fully implemented + if (!iSubLayer && !IsComplete()) + User::Leave(KErrCorrupt); + } + +void CCdlDllInstance::SetIsCompleteFlag(TInt aRequiredApiSize) + { + if (iInterface->iApiSize >= aRequiredApiSize) + { + iFlags |= KCdlInstanceFlagIsComplete; + TAny** pApi = iApi; + TAny** end = iApi + iInterface->iApiSize; + for (; pApi != end; ++pApi) + { + if (!*pApi) + { + iFlags &= ~KCdlInstanceFlagIsComplete; + break; + } + } + } + else + { + iFlags &= ~KCdlInstanceFlagIsComplete; + } + } + +const RCdlLibRef& CCdlDllInstance::Lib() const + { + return iLib; + } + +TBool CCdlDllInstance::IsComplete() const + { + return iFlags & KCdlInstanceFlagIsComplete; + } + +TAny* CCdlDllInstance::Implementation(TInt aCdlApiId) const + { + return iApi[aCdlApiId]; + } + +const SCdlInterface& CCdlDllInstance::Interface() const + { + return *iInterface; + } + + +// +// CCdlInstanceProxy +// + +CCdlInstanceProxy::CCdlInstanceProxy(CCdlEngine* aEngine, TInt* aLastApi) +: CCdlInstance(aEngine, aLastApi) + { + } + +void CCdlInstanceProxy::Set(const CCdlInstance& aInst) + { + iInst = &aInst; + iRef = iInst->Ref(); + iSubLayer = iInst->SubLayer(); + } + +TBool CCdlInstanceProxy::IsComplete() const + { + __ASSERT_ALWAYS(iInst, Panic(ECdlEngPanic_ProxyNotInitialised)); + return iInst->IsComplete(); + } + +TAny* CCdlInstanceProxy::Implementation(TInt aCdlApiId) const + { + __ASSERT_ALWAYS(iInst, Panic(ECdlEngPanic_ProxyNotInitialised)); + return iInst->Implementation(aCdlApiId); + } + +const SCdlInterface& CCdlInstanceProxy::Interface() const + { + __ASSERT_ALWAYS(iInst, Panic(ECdlEngPanic_ProxyNotInitialised)); + return iInst->Interface(); + } + + +// +// CCdlCustomisationStack +// + +CCdlCustomisationStack* CCdlCustomisationStack::NewLC(TUid aCdlUid, CCdlEngine* aEngine) + { + CCdlCustomisationStack* self = new(ELeave) CCdlCustomisationStack(aCdlUid, aEngine); + CleanupStack::PushL(self); + self->ConstructL(); + return self; + } + +CCdlCustomisationStack::~CCdlCustomisationStack() + { + delete iTopProxy; + iStack.ResetAndDestroy(); + } + +const CCdlInstance* CCdlCustomisationStack::LastAccessedInstance() const + { + __ASSERT_ALWAYS(iTop, Panic(ECdlEngPanic_NoInstanceLoaded)); + return iTop->Implementor(iLastApiId); + } + +CCdlCustomisationStack::CCdlCustomisationStack(TUid aUid, CCdlEngine* aEngine) +: iUid(aUid), iStack(KCustomisationStackGranularity), + iGlobalCustomisationEnabled(ETrue), iEngine(aEngine) + { + } + +void CCdlCustomisationStack::ConstructL() + { + iTopProxy = new(ELeave) CCdlInstanceProxy(iEngine, &iLastApiId); + iTopProxy->ReleaseRef(); // we don't want a reference to the engine owned by engine + } + +void CCdlCustomisationStack::RequireCustomisationL(const SCdlInterface* aInterfaceParams) + { + if (!iInterfaceParams) + iInterfaceParams = aInterfaceParams; + else if (CompareInterfaces(aInterfaceParams, iInterfaceParams) > 0) + User::Leave(KErrNotSupported); + } + +void CCdlCustomisationStack::ClearOverrides() + { + if (iTop) + { + Delete(1, iStack.Count()-1); // remove everything but the base + iTop = iStack[0]; + iTopProxy->Set(*iTop); + } + } + +void CCdlCustomisationStack::LoadCustomisationL(const TCdlRef& aRef) + { + CCdlInstance* cust = NewInstanceLC(aRef); + if (InstanceCanBeBase(cust)) + { // this customisation is sufficient to form a new base and doesn't change ROM-only flag + NewBaseL(cust); + CleanupStack::Pop(cust); + } + else if (!iTop) + { // there must be an existing base before this customisation can be used + User::Leave(KErrCorrupt); + } + else if (*cust == *iTop) + { // don't layer the same customisation over itself - no point + CleanupStack::PopAndDestroy(cust); + } + else + { // this is a partial customisation + PushCustL(cust); + CleanupStack::Pop(cust); + } + } + +CCdlInstance* CCdlCustomisationStack::NewInstanceLC(const TCdlRef& aRef) + { + // these temporary params are only used when no interface has been set + SCdlInterface tempParams = + { + 0, // iMajorEngVer + 0, // iMinorEngVer + 0, // iName + {aRef.iUid.iUid}, // iUid + 0, // iMajorVer + 0, // iMinorVer + 0, // iFlags + 0 // iApiSize + }; + const SCdlInterface* iface = iInterfaceParams ? iInterfaceParams : &tempParams; + return CCdlInstance::NewLC(aRef, iface, iTop, iEngine, &iLastApiId); + } + +const CCdlInstance& CCdlCustomisationStack::Top() const + { + return *iTopProxy; + } + +TInt* CCdlCustomisationStack::LastApiRef() const + { + return &iLastApiId; + } + +void CCdlCustomisationStack::NewBaseL(CCdlInstance* aBase) + { + PushCustL(aBase); + iInterfaceParams = &aBase->Interface(); + Delete(0, iStack.Count()-1); // remove everything but the new base + } + +void CCdlCustomisationStack::PushCustL(CCdlInstance* aCust) + { + iStack.AppendL(aCust); + aCust->ReleaseRef(); // we don't want a reference to the engine owned by engine + iTop = aCust; + iTopProxy->Set(*iTop); + } + +void CCdlCustomisationStack::Delete(TInt aPos, TInt aCount) + { + for (TInt ii=0; ii= 0); + return iTop && apiIsSupported; + } + +// this returns 0 for same, >0 for aLeft better than aRight and <0 otherwise +TInt CCdlCustomisationStack::CompareInterfaces(const SCdlInterface* aLeft, const SCdlInterface* aRight) + { + // first, pointer checks + if (!aLeft && !aRight) + return 0; + else if (!aRight) + return 1; + else if (!aLeft) + return -1; + // next, ROM only flag checks + else if ((aLeft->iFlags&KCdlFlagRomOnly) && !(aRight->iFlags&KCdlFlagRomOnly)) + return 1; + else if (!(aLeft->iFlags&KCdlFlagRomOnly) && (aRight->iFlags&KCdlFlagRomOnly)) + return -1; + // finally, API size check + return aLeft->iApiSize - aRight->iApiSize; + } + +TBool CCdlCustomisationStack::InstanceCanBeBase(CCdlInstance* aInst) const + { + return + CompareInterfaces(&aInst->Interface(), iInterfaceParams) >= 0 && + aInst->IsComplete() && + ( // check that ROM only flag does not change + !iInterfaceParams || + (aInst->Interface().iFlags&KCdlFlagRomOnly) == (iInterfaceParams->iFlags&KCdlFlagRomOnly) + ); + }