layouts/cdl/CdlEngine/src/CdlCustomisation.cpp
changeset 0 05e9090e2422
--- /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 <f32file.h>
+
+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<aCount; ii++)
+		delete iStack[aPos+ii];
+	iStack.Delete(aPos, aCount);
+	}
+
+TBool CCdlCustomisationStack::IsCustomisationStarted(const SCdlInterface* aInterfaceParams) const
+	{
+	TBool apiIsSupported = (CompareInterfaces(iInterfaceParams, aInterfaceParams) >= 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)
+		);
+	}