sysstatemgmt/systemstatemgr/cmd/src/ssmcommandlistresourcereaderimpl.cpp
changeset 0 4e1aa6a622a0
child 3 a811597961f0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sysstatemgmt/systemstatemgr/cmd/src/ssmcommandlistresourcereaderimpl.cpp	Tue Feb 02 00:53:00 2010 +0200
@@ -0,0 +1,834 @@
+// Copyright (c) 2007-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 "ssmcommandlistresourcereaderimpl.h"
+
+#include <bautils.h>
+#include <barsc2.h>
+#include <ssm/ssmcommandlist.h>
+#include <ssm/ssmconditionalcallback.h>
+
+#include <ssm/ssmcommandfactory.h>
+#include <ssm/ssmcommand.h>
+#include "ssmcommandbase.h"
+#include "ssmcommandparameters.h"
+#include "ssmcommandlistinterface.h"
+#include "ssmdebug.h"
+#include "ssmpanic.h"
+#ifdef SYMBIAN_SSM_FLEXIBLE_MERGE
+#include "ssmcommandlistimpl.h"
+#endif
+
+CSsmCommandListResourceReaderImpl* CSsmCommandListResourceReaderImpl::NewL(RFs& aFs, const TDesC& aCommandListPath, MSsmConditionalCallback& aConditionalCallback)
+	{
+	CSsmCommandListResourceReaderImpl* self = new(ELeave) CSsmCommandListResourceReaderImpl();
+	CleanupStack::PushL(self);
+	self->ConstructL(aFs, aCommandListPath, aConditionalCallback);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+CSsmCommandListResourceReaderImpl::CSsmCommandListResourceReaderImpl()
+	{
+	}
+
+CSsmCommandListResourceReaderImpl::~CSsmCommandListResourceReaderImpl()
+	{
+	delete iPreparer;
+	delete iInitialiser;
+	delete iResourcePool;
+	}
+
+void CSsmCommandListResourceReaderImpl::ConstructL(RFs& aFs, const TDesC& aCommandListPath, MSsmConditionalCallback& aConditionalCallback)
+	{
+	iResourcePool = new(ELeave) CResourcePool;
+	iInitialiser = CInitialiser::NewL(aFs, aCommandListPath, *iResourcePool);
+	iPreparer = new(ELeave) CPreparer(*iResourcePool, aConditionalCallback);
+	}
+
+void CSsmCommandListResourceReaderImpl::Initialise(TRequestStatus& aStatus)
+	{
+	__ASSERT_ALWAYS(!Busy(), PanicNow(KPanicCmdResourceReader, EInUse1));
+	iInitialiser->Start(aStatus);
+	}
+
+void CSsmCommandListResourceReaderImpl::InitialiseCancel()
+	{
+	iInitialiser->Cancel();
+	}
+
+void CSsmCommandListResourceReaderImpl::PrepareCommandList(MSsmCommandList& aCommandList, TInt aCommandListId, const TSsmState& aState, TRequestStatus& aStatus)
+	{
+	__ASSERT_ALWAYS(!Busy(), PanicNow(KPanicCmdResourceReader, EInUse2));
+	iPreparer->Start(aCommandList, aCommandListId, aState, aStatus);
+	}
+
+void CSsmCommandListResourceReaderImpl::PrepareCommandList(MSsmCommandList& aCommandList, TInt aCommandListId, const TSsmSwp& aSwp, TRequestStatus& aStatus)
+	{
+	__ASSERT_ALWAYS(!Busy(), PanicNow(KPanicCmdResourceReader, EInUse3));
+	iPreparer->Start(aCommandList, aCommandListId, aSwp, aStatus);
+	}
+
+void CSsmCommandListResourceReaderImpl::PrepareCommandListCancel()
+	{
+	iPreparer->Cancel();
+	}
+
+TBool CSsmCommandListResourceReaderImpl::IsCommandListReady() const
+	{
+	// enables caller to find out if the command list they passed
+	// to PrepareCommandList is fully prepared or not
+	return iPreparer->IsCommandListReady();
+	}
+
+TBool CSsmCommandListResourceReaderImpl::Busy() const
+	{
+	return iInitialiser->IsActive() || iPreparer->IsActive();
+	}
+
+void CSsmCommandListResourceReaderImpl::GetCommandListIdsL(RArray<TInt>& aArray) const
+	{
+	iResourcePool->GetCommandListIdsL(aArray);
+	}
+
+// CResourcePool
+CSsmCommandListResourceReaderImpl::CResourcePool::CResourcePool()
+	{
+	}
+
+CSsmCommandListResourceReaderImpl::CResourcePool::~CResourcePool()
+	{
+	iMappings.Close();
+	iResourceFiles.ResetAndDestroy();
+	iResourceFileNames.ResetAndDestroy();
+	}
+
+TBool CSsmCommandListResourceReaderImpl::CResourcePool::IsEmpty() const
+	{
+	return !(iMappings.Count() > 0);
+	}
+
+void CSsmCommandListResourceReaderImpl::CResourcePool::Reset()
+	{
+	iMappings.Reset();
+	iResourceFiles.ResetAndDestroy();
+	iResourceFileNames.ResetAndDestroy();
+	}
+
+void CSsmCommandListResourceReaderImpl::CResourcePool::AppendL(const CResourceFile* aResourceFile)
+	{
+	iResourceFiles.AppendL(aResourceFile);
+	}
+
+void CSsmCommandListResourceReaderImpl::CResourcePool::AppendL(const TDesC& aFileName)
+	{
+	HBufC* name = aFileName.AllocLC();
+	iResourceFileNames.AppendL(name);
+	CleanupStack::Pop(name);
+	}
+
+
+void CSsmCommandListResourceReaderImpl::CResourcePool::AppendL(const TMapping& aMapping)
+	{
+#ifdef SYMBIAN_SSM_FLEXIBLE_MERGE 
+	//check if the mapping already exists
+	TInt index = iMappings.Find(aMapping);
+	if (index != KErrNotFound)
+		{
+		DEBUGPRINT2(_L("Duplicate Substate found at index: %d"), index);
+		}
+	TInt err = iMappings.InsertInSignedKeyOrderAllowRepeats(aMapping);
+#else
+	TInt err = iMappings.InsertInSignedKeyOrder(aMapping); 
+    if(KErrAlreadyExists == err) 
+		{ 
+		PanicNow(KPanicCmdResourceReader, EDuplicateSubstateInCommandList); 
+		} 
+#endif
+    User::LeaveIfError(err);     
+	}
+
+#ifdef SYMBIAN_SSM_FLEXIBLE_MERGE
+// This function will get all the mappings which have the same commandlistId's (substates) into aMappingArray
+void CSsmCommandListResourceReaderImpl::CResourcePool::UpdateMappingArrayL(TInt aCommandListId, RArray<TMapping>& aMappingArray) const
+	{
+	aMappingArray.Reset();
+	TMapping mapping(aCommandListId, 0, NULL);
+	const TInt mappingCount = iMappings.Count();
+	TInt mappingIndex = iMappings.FindL(mapping);
+
+	for(; mappingIndex < mappingCount; ++mappingIndex)
+		{
+		aMappingArray.AppendL(iMappings[mappingIndex]);
+		if ((mappingIndex >= (mappingCount - 1)) || (iMappings[mappingIndex].iCommandListId !=
+		iMappings[mappingIndex + 1].iCommandListId))
+			{
+			//Breaking as it reached end of array or completed appending the mappings for
+			//the given commandlist id
+			break;
+			}
+		}
+	DEBUGPRINT3(_L("Mapping Array for substate %d Contains %d entries"), iMappings[mappingIndex].iCommandListId, aMappingArray.Count());
+	}
+
+#else
+CSsmCommandListResourceReaderImpl::TMapping CSsmCommandListResourceReaderImpl::CResourcePool::MappingL(TInt aCommandListId) const
+	{
+	TMapping mapping(aCommandListId, 0, NULL);
+	const TInt index = iMappings.FindL(mapping);
+	return iMappings[index];
+	}
+
+#endif
+void CSsmCommandListResourceReaderImpl::CResourcePool::GetCommandListIdsL(RArray<TInt>& aArray) const
+	{
+	TInt count = iMappings.Count();
+	__ASSERT_ALWAYS(count > 0, PanicNow(KPanicCmdResourceReader, ENotInitialized3));
+	if (aArray.Count() != 0)
+		{
+		SSMLOGLEAVE(KErrArgument);
+		}
+	aArray.ReserveL(count);
+#ifdef SYMBIAN_SSM_FLEXIBLE_MERGE
+	TInt i = 0;
+	for(i = 0; i < iMappings.Count() - 1 ; ++i)
+		{
+		if(iMappings[i].iCommandListId != iMappings[i+1].iCommandListId)
+			{
+			aArray.AppendL(iMappings[i].iCommandListId);
+			}
+		}
+	//append the last element anyway as it is already compared
+	aArray.AppendL(iMappings[i].iCommandListId);
+	aArray.Compress();
+		
+	DEBUGPRINT2(_L("The number of substates in resource files : %d"),iMappings.Count() );
+	DEBUGPRINT2(_L("The number of substates after filtering duplicates : %d"),aArray.Count());
+#else
+	for(TInt i = 0; i < count; ++i)
+		{
+		aArray.AppendL(iMappings[i].iCommandListId);
+		}
+#endif
+	}
+
+const TDesC& CSsmCommandListResourceReaderImpl::CResourcePool::FileNameForResourceFileL(const CResourceFile* aResourceFile) const
+	{
+	TInt count = iResourceFiles.Count();
+	for(TInt i = 0; i < count; ++i)
+		{
+		if(iResourceFiles[i] == aResourceFile)
+			{
+			return *iResourceFileNames[i];
+			}
+		}
+	SSMLOGLEAVE(KErrNotFound);
+	return KNullDesC16();
+	}
+
+// CActiveBase
+CSsmCommandListResourceReaderImpl::CActiveBase::CActiveBase(TInt aPriority)
+	:CActive(aPriority), iAction(EIdle)
+	{
+	}
+
+CSsmCommandListResourceReaderImpl::CActiveBase::~CActiveBase()
+	{
+	}
+
+void CSsmCommandListResourceReaderImpl::CActiveBase::Start()
+	{
+	TRequestStatus* status = &iStatus;
+	User::RequestComplete(status, KErrNone);
+	SetActive();
+	}
+
+void CSsmCommandListResourceReaderImpl::CActiveBase::CompleteClientRequest(TInt aReason)
+	{
+	if (iRequestStatus)
+		{
+		User::RequestComplete(iRequestStatus, aReason);
+		iRequestStatus = NULL;
+		}
+	}
+
+// CInitialiser
+CSsmCommandListResourceReaderImpl::CInitialiser* CSsmCommandListResourceReaderImpl::CInitialiser::NewL(RFs& aFs, const TDesC& aCommandListPath, CResourcePool& aResourcePool)
+	{
+	CInitialiser* self = new(ELeave) CInitialiser(aFs, aResourcePool);
+	CleanupStack::PushL(self);
+	self->ConstructL(aCommandListPath);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+CSsmCommandListResourceReaderImpl::CInitialiser::CInitialiser(RFs& aFs, CResourcePool& aResourcePool)
+	:CActiveBase(EPriorityStandard),  iFs(aFs), iResourcePool(aResourcePool)
+	{
+	CActiveScheduler::Add(this);
+	}
+
+CSsmCommandListResourceReaderImpl::CInitialiser::~CInitialiser()
+	{
+	Cancel();
+	ResetToUninitialisedState();
+	iPath.Close();
+#ifdef SYMBIAN_SSM_FLEXIBLE_MERGE
+	iSystemDrivePath.Close();
+#endif
+	}
+
+void CSsmCommandListResourceReaderImpl::CInitialiser::ResetToUninitialisedState()
+	{
+	delete iResourceFileEntries;
+	iResourceFileEntries = NULL;
+	iEntryIndex = 0;
+	iResourcePool.Reset();
+	iAction = EIdle;
+#ifdef SYMBIAN_SSM_FLEXIBLE_MERGE
+	delete iRssFileEntriesInSysDrive;
+	iRssFileEntriesInSysDrive = NULL;
+#endif
+	}
+
+void CSsmCommandListResourceReaderImpl::CInitialiser::ConstructL(const TDesC& aCommandListPath)
+	{
+	if (aCommandListPath.Length() == 0)
+		{
+		SSMLOGLEAVE(KErrArgument);
+		}
+	iPath.CreateL(aCommandListPath);
+#ifdef SYMBIAN_SSM_FLEXIBLE_MERGE
+	// get the system drive char and create system drive path 
+	TChar systemDriveChar = iFs.GetSystemDriveChar();
+	//append the system drive
+	iSystemDrivePath.CreateL(iPath.MaxLength());
+	iSystemDrivePath.Append(systemDriveChar);
+	//append the system drive path which is same as ROM drive path minus ROM drive char 
+	iSystemDrivePath.Append(iPath.Right(iPath.Length()-1));
+#endif
+	}
+
+void CSsmCommandListResourceReaderImpl::CInitialiser::Start(TRequestStatus& aStatus)
+	{
+	__ASSERT_ALWAYS(iRequestStatus == NULL, PanicNow(KPanicCmdResourceReader, EInUse1));
+	aStatus = KRequestPending;
+	iRequestStatus = &aStatus;
+
+	iAction = EInitialiseFirstStep;
+	CActiveBase::Start();
+	}
+
+/**
+@panic ENonNullResourceFileEntries if the Resource File Entries is Not Null
+@panic ENullResourceFileEntries if the Resource File Entries is Null
+@panic EInvalidRunLAction if the RunL Action is invalid
+*/
+void CSsmCommandListResourceReaderImpl::CInitialiser::RunL()
+	{
+	SSMLOGLEAVEIFERROR(iStatus.Int());
+
+	switch (iAction)
+		{
+	case EInitialiseFirstStep:
+		DoInitialiseFirstStepL();
+		break;
+	case EInitialiseNextStep:
+		DoInitialiseNextStepL();
+		break;
+#ifdef SYMBIAN_SSM_FLEXIBLE_MERGE
+	case EInitialiseSysDriveStep:
+		DoInitialiseSysDriveStepL();
+		break;		
+#endif
+	default:
+		PanicNow(KPanicCmdResourceReader, EInvalidRunLAction);
+		break;
+		}
+
+	if (iAction == EIdle)
+		{
+		CompleteClientRequest(KErrNone); // must not leave between here and end of RunL
+		return;
+		}
+
+	CActiveBase::Start(); // run again
+	}
+
+void CSsmCommandListResourceReaderImpl::CInitialiser::DoCancel()
+	{
+	// iStatus is always completed before this object is set active, so no need to complete iStatus with KErrCancel
+	CompleteClientRequest(KErrCancel);
+	ResetToUninitialisedState();
+	}
+
+TInt CSsmCommandListResourceReaderImpl::CInitialiser::RunError(TInt aError)
+	{
+	DEBUGPRINT2(_L("Resource reader initialiser reason (%d)"), aError);
+	CompleteClientRequest(aError);
+	ResetToUninitialisedState();
+	return KErrNone;
+	}
+
+void CSsmCommandListResourceReaderImpl::CInitialiser::DoInitialiseFirstStepL()
+	{
+	if (!iResourcePool.IsEmpty())
+		{
+		// already initialised, don't count this as an error
+		iAction = EIdle;
+		return;
+		}
+
+	// get list of command list resource filenames
+	TFileName path(iPath);
+	_LIT(KStar, "*");
+	path.Append(KStar);
+	const TUid KUidResourceFile = {0x101f4a6b};
+	__ASSERT_ALWAYS(iResourceFileEntries == NULL, PanicNow(KPanicCmdResourceReader, ENonNullResourceFileEntries));
+	// The error cannot be KErrPathNotFound as fallback will be used if there is not startup path
+	// Even if there are no resource files, this succeeds
+	// User::LeaveIfError handles other error conditions
+	User::LeaveIfError(iFs.GetDir(path, TUidType(KUidResourceFile, TUid::Uid(KUidSsmCommandListResourceFile)), ESortNone, iResourceFileEntries));
+	iEntryIndex = iResourceFileEntries->Count();
+
+#ifdef SYMBIAN_SSM_FLEXIBLE_MERGE
+	DEBUGPRINT2(_L("Number of resource files in ROM Drive : %d"),iEntryIndex );
+	// Now, get list of command list resource filenames from system drive too
+	TFileName sysPath(iSystemDrivePath);
+	sysPath.Append(KStar);
+	TInt err = (iFs.GetDir(sysPath, TUidType(KUidResourceFile, TUid::Uid(KUidSsmCommandListResourceFile)), ESortNone, iRssFileEntriesInSysDrive));
+	if (KErrNone == err)
+		{
+		iSysDriveEntryIndex = iRssFileEntriesInSysDrive->Count();
+		DEBUGPRINT2(_L("Number of resource files in System Drive : %d"),iSysDriveEntryIndex );
+		}
+	// all other error conditions are ignored as there is no compulsion for resource files to be present on system drive
+	else if(KErrPathNotFound == err)
+		{
+		//the path for SCLs on system drive does not exist
+		DEBUGPRINT1(_L("System Drive does not contain command lists"));
+		}
+	if(iEntryIndex == 0 && iSysDriveEntryIndex == 0)
+		{
+		DEBUGPRINT3(_L("Command list resource file directories (%S) and (%S) do not contain any command list resource files"), &path, &sysPath);
+		SSMLOGLEAVE(KErrNotFound);
+		}
+#else
+	if (iEntryIndex == 0)
+		{
+		DEBUGPRINT2(_L("Command list resource file directory (%S) does not contain any command list resource files"), &path);
+		SSMLOGLEAVE(KErrNotFound);
+		}
+#endif
+	iAction = EInitialiseNextStep;
+	}
+
+void CSsmCommandListResourceReaderImpl::CInitialiser::DoInitialiseNextStepL()
+	{
+	__ASSERT_ALWAYS(iResourceFileEntries != NULL, PanicNow(KPanicCmdResourceReader, ENullResourceFileEntries));
+	if (iEntryIndex--)
+		{
+		TFileName filename(iPath);
+		filename.Append((*iResourceFileEntries)[iEntryIndex].iName);
+		CResourceFile* const resourceFile = OpenResourceFileL(filename);
+		ParseFileL(resourceFile);
+		}
+
+	else
+		{
+#ifdef SYMBIAN_SSM_FLEXIBLE_MERGE
+		iAction = EInitialiseSysDriveStep;
+#else
+		// initialisation complete
+		iAction = EIdle;
+#endif
+		delete iResourceFileEntries;
+		iResourceFileEntries = NULL;
+		}
+	}
+
+#ifdef SYMBIAN_SSM_FLEXIBLE_MERGE
+void CSsmCommandListResourceReaderImpl::CInitialiser::DoInitialiseSysDriveStepL()
+	{
+	if (iSysDriveEntryIndex--)
+		{
+		TFileName filename(iSystemDrivePath);
+		filename.Append((*iRssFileEntriesInSysDrive)[iSysDriveEntryIndex].iName);
+		CResourceFile* const resourceFile = OpenResourceFileL(filename);
+		ParseFileL(resourceFile);
+		}
+	else
+		{
+		// initialisation complete
+		iAction = EIdle;
+		delete iRssFileEntriesInSysDrive;
+		iRssFileEntriesInSysDrive = NULL;
+		}
+	}
+#endif
+CResourceFile* CSsmCommandListResourceReaderImpl::CInitialiser::OpenResourceFileL(const TDesC& aFileName)
+	{
+
+	// open the resource file
+	RFile file;
+	CleanupClosePushL(file);
+	User::LeaveIfError(file.Open(iFs, aFileName, EFileRead | EFileShareReadersOnly));
+
+	// read entire resource file into a buffer
+	TInt fileSize;
+	User::LeaveIfError(file.Size(fileSize));
+	RBuf8 buf;
+	buf.CreateL(fileSize);
+	CleanupClosePushL(buf);
+	User::LeaveIfError(file.Read(buf));
+
+	// create a CResourceFile from the buffer and add it to array (the CResourceFile takes its own copy of the buffer)
+	CResourceFile* const resourceFile = CResourceFile::NewL(buf);
+	CleanupStack::PushL(resourceFile);
+	iResourcePool.AppendL(resourceFile);
+	CleanupStack::Pop(resourceFile);
+	iResourcePool.AppendL(aFileName);
+	CleanupStack::PopAndDestroy(&buf);
+	CleanupStack::PopAndDestroy(&file);
+	return resourceFile;
+	}
+
+void CSsmCommandListResourceReaderImpl::CInitialiser::ParseFileL(CResourceFile* aResourceFile)
+	{
+	// read root resource
+	RResourceReader rootReader;
+	const TInt KRootResourceId = 1;
+	rootReader.OpenLC(aResourceFile, KRootResourceId);
+	const TSsmResourceVersion version = static_cast<TSsmResourceVersion>(rootReader.ReadInt16L());
+	if (version != ESsmInitialVersion)
+		{
+		SSMLOGLEAVE(KErrNotSupported);
+		}
+	const TInt reserved1 = rootReader.ReadInt16L(); // skip SSM_COMMAND_LIST_ROOT.reserved1
+	const TInt commandListMappingResourceId = rootReader.ReadInt32L();
+	if (commandListMappingResourceId <= 0)
+		{
+		DEBUGPRINT1(_L("Command list resource file contains no mappings"));
+		SSMLOGLEAVE(KErrNotFound);
+		}
+	CleanupStack::PopAndDestroy(&rootReader);
+
+	// read mapping resource
+	RResourceReader mappingReader;
+	mappingReader.OpenLC(aResourceFile, commandListMappingResourceId);
+	const TInt mappingCount = mappingReader.ReadInt16L();
+	if (!mappingCount)
+		{
+		DEBUGPRINT1(_L("Command list resource file contains no mappings"));
+		SSMLOGLEAVE(KErrNotFound);
+		}
+	for (TInt i = 0; i < mappingCount; i++)
+		{
+		// add each mapping to the pool
+		TUint commandListId = mappingReader.ReadUint32L();
+		TInt resourceId = mappingReader.ReadInt32L();
+		TMapping mapping(commandListId, resourceId, aResourceFile);
+		iResourcePool.AppendL(mapping);
+		}
+	CleanupStack::PopAndDestroy(&mappingReader);
+	}
+
+// CPreparer
+CSsmCommandListResourceReaderImpl::CPreparer::CPreparer(const CResourcePool& aResourcePool, MSsmConditionalCallback& aConditionalCallback)
+	:CActiveBase(EPriorityStandard), iResourcePool(aResourcePool), iConditionalCallback(aConditionalCallback), iSwpChange(0, 0), iMapping(0, 0, NULL)
+	{
+	CActiveScheduler::Add(this);
+	}
+
+CSsmCommandListResourceReaderImpl::CPreparer::~CPreparer()
+	{
+	Cancel();
+	ResetReadyForNextPrepare();
+	}
+
+void CSsmCommandListResourceReaderImpl::CPreparer::Start(MSsmCommandList& aCommandList, TInt aCommandListId, const TSsmState& aState, TRequestStatus& aStatus)
+	{
+	__ASSERT_ALWAYS(iRequestStatus == NULL, PanicNow(KPanicCmdResourceReader, EInUse2));
+	__ASSERT_ALWAYS(!iResourcePool.IsEmpty(), PanicNow(KPanicCmdResourceReader, ENotInitialized));
+	aStatus = KRequestPending;
+	iRequestStatus = &aStatus;
+
+	iCommandList = &aCommandList;
+	iCommandListId = aCommandListId;
+	iState = aState;
+	iCommandListReady = EFalse;
+
+	iAction = EPrepareFirstStep;
+	CActiveBase::Start();
+	}
+
+void CSsmCommandListResourceReaderImpl::CPreparer::Start(MSsmCommandList& aCommandList, TInt aCommandListId, const TSsmSwp& aSwp, TRequestStatus& aStatus)
+	{
+	__ASSERT_ALWAYS(iRequestStatus == NULL, PanicNow(KPanicCmdResourceReader, EInUse3));
+	__ASSERT_ALWAYS(!iResourcePool.IsEmpty(), PanicNow(KPanicCmdResourceReader, ENotInitialized2));
+	aStatus = KRequestPending;
+	iRequestStatus = &aStatus;
+
+	iCommandList = &aCommandList;
+	iCommandListId = aCommandListId;
+	iSwpChange = aSwp;
+	iCommandListReady = EFalse;
+
+	iAction = EPrepareFirstStep;
+	CActiveBase::Start();
+	}
+
+/**
+@panic EInvalidRunLAction if the RunL Action is invalid
+*/
+void CSsmCommandListResourceReaderImpl::CPreparer::RunL()
+	{
+	SSMLOGLEAVEIFERROR(iStatus.Int());
+
+	switch (iAction)
+		{
+	case EPrepareFirstStep:
+		DoPrepareFirstStepL();
+		break;
+	case EPrepareNextStep:
+		DoPrepareNextStepL();
+		break;
+	default:
+		PanicNow(KPanicCmdResourceReader, EInvalidRunLAction);
+		break;
+		}
+
+	if (iAction == EIdle)
+		{
+		CompleteClientRequest(KErrNone); // must not leave between here and end of RunL
+		return;
+		}
+
+	CActiveBase::Start(); // run again
+	}
+
+void CSsmCommandListResourceReaderImpl::CPreparer::DoCancel()
+	{
+	// iStatus is always completed before this object is set active, so no need to complete iStatus with KErrCancel
+	CompleteClientRequest(KErrCancel);
+	ResetReadyForNextPrepare();
+	}
+
+TInt CSsmCommandListResourceReaderImpl::CPreparer::RunError(TInt aError)
+	{
+	DEBUGPRINT2(_L("Resource reader preparer reason (%d)"), aError);
+	CompleteClientRequest(aError);
+	ResetReadyForNextPrepare();
+	return KErrNone;
+	}
+
+TBool CSsmCommandListResourceReaderImpl::CPreparer::IsCommandListReady()
+	{
+	// enables caller to find out if the command list they passed
+	// to PrepareCommandList is fully prepared or not
+	if (iCommandListReady)
+		{
+		iCommandListReady = EFalse;
+		return ETrue;
+		}
+	return EFalse;
+	}
+
+void CSsmCommandListResourceReaderImpl::CPreparer::ResetReadyForNextPrepare()
+	{
+	iListReader.Close();
+	iCommandIndex = 0;
+	iCommandListReady = EFalse;
+	iAction = EIdle;
+#ifdef SYMBIAN_SSM_FLEXIBLE_MERGE
+	iCommandIndexInRssFile.Reset();
+	iMappingArray.Reset();
+#endif
+	}
+
+
+void CSsmCommandListResourceReaderImpl::CPreparer::DoPrepareFirstStepL()
+	{
+#ifdef SYMBIAN_SSM_FLEXIBLE_MERGE
+	iCurrentCommandListInMapping = 0;
+	iResourcePool.UpdateMappingArrayL(iCommandListId,iMappingArray);
+	TInt substateCount = iMappingArray.Count();
+	iCommandIndexInRssFile.ReserveL(substateCount);
+	
+	// get number of commands from all the lists
+	for(TInt substateIndex = 0; substateIndex < substateCount; ++substateIndex )
+		{
+		iListReader.OpenL(iMappingArray[substateIndex].iResourceFile, iMappingArray[substateIndex].iResourceId);
+		//advancing the pointer to point to number of commands in list
+		iListReader.AdvanceL(sizeof(TInt32));
+		iCommandIndexInRssFile.AppendL(iListReader.ReadUint16L());
+		iCommandIndex +=  iCommandIndexInRssFile[substateIndex]; 
+		iListReader.Close();
+		}
+	//open the first resource id and read the commands.
+	iListReader.OpenL(iMappingArray[iCurrentCommandListInMapping].iResourceFile, iMappingArray[iCurrentCommandListInMapping].iResourceId);
+	// the delay between the commands is read from only the frist command list. In case of other lists, it is ignored.
+	iCommandList->SetDelayBetweenCommands(iListReader.ReadInt32L());
+	iCommandList->SetResourceFileNameL(iResourcePool.FileNameForResourceFileL(iMappingArray[iCurrentCommandListInMapping].iResourceFile));
+	//skip reading command count again and jump to command resourceId
+	iListReader.AdvanceL(sizeof(TUint16));
+#else
+	iMapping = iResourcePool.MappingL(iCommandListId);
+	iListReader.OpenL(iMapping.iResourceFile, iMapping.iResourceId);
+	iCommandList->SetDelayBetweenCommands(iListReader.ReadInt32L());
+	iCommandIndex = iListReader.ReadUint16L(); // command count
+
+	// Set up the resource file name for this list
+	iCommandList->SetResourceFileNameL(iResourcePool.FileNameForResourceFileL(iMapping.iResourceFile));
+#endif
+	
+	// Set up the conditional callback
+	iCommandList->SetConditionalCallback(iConditionalCallback);
+	
+	iAction = EPrepareNextStep;
+	}
+
+void CSsmCommandListResourceReaderImpl::CPreparer::DoPrepareNextStepL()
+	{
+	const TInt KBatchSize = 5; // Max number of commands prepared per RunL, this may need to be adjusted if responsiveness is a problem
+	iBatchIndex = KBatchSize;
+			
+#ifdef SYMBIAN_SSM_FLEXIBLE_MERGE
+	TBool inProgress = ETrue;
+	while (inProgress && iBatchIndex --)
+		{
+		if (iCommandIndexInRssFile[iCurrentCommandListInMapping] == 0 )
+			{
+			//the current command list is parsed and all commands added
+			// go to the next commnad list
+			++iCurrentCommandListInMapping;
+			
+			if ( (iCurrentCommandListInMapping+1) > iCommandIndexInRssFile.Count() )
+				{
+				// all command lists are processed. Set the inProgress flag to "EFalse" 
+				inProgress = EFalse;
+				break;
+				}
+			else
+				{
+				//open the next resource id and read the commands
+				iListReader.Close();
+				iListReader.OpenL(iMappingArray[iCurrentCommandListInMapping].iResourceFile, iMappingArray[iCurrentCommandListInMapping].iResourceId);
+				// skipping delay between commands as it is already set from first rss file
+				iListReader.AdvanceL(sizeof(TInt32));
+				iCommandList->SetResourceFileNameL(iResourcePool.FileNameForResourceFileL(iMappingArray[iCurrentCommandListInMapping].iResourceFile));
+				//skip reading command count again and jump to command resourceId
+				iListReader.AdvanceL(sizeof(TUint16));
+				}
+			}
+		DEBUGPRINT2A("The value of RssFile's current command is %d ", iCommandIndexInRssFile[iCurrentCommandListInMapping]);
+#else
+	while(iCommandIndex && iBatchIndex--)
+		{
+		--iCommandIndex; // Note: can't decrement in while expression above, incase iBatchIndex is zero
+#endif
+		// open command resource
+		const TInt commandResourceId = iListReader.ReadInt32L();
+		DEBUGPRINT2A("Reading command resource id %x", commandResourceId);
+		RResourceReader commandReader;
+#ifdef SYMBIAN_SSM_FLEXIBLE_MERGE
+		commandReader.OpenLC(iMappingArray[iCurrentCommandListInMapping].iResourceFile, commandResourceId);
+#else
+		commandReader.OpenLC(iMapping.iResourceFile, commandResourceId);
+#endif
+		// read conditional imformation
+		const TInt conditionalInfoResourceId = commandReader.ReadInt32L();
+
+		// read command type
+		const TSsmCommandType type = static_cast<TSsmCommandType>(commandReader.ReadInt16L());
+		commandReader.RewindL(sizeof(TInt16)); // commands expect reader to be pointing to the command type
+		
+		// construct command and add to command list
+		TRAPD(err, AddCommandToListL(type, commandReader, conditionalInfoResourceId));
+		if(KErrNone != err)
+			{
+			DEBUGPRINT2A("Failed to add command of type: %d", type);
+			}
+		SSMLOGLEAVEIFERROR(err);
+		CleanupStack::PopAndDestroy(&commandReader);
+#ifdef SYMBIAN_SSM_FLEXIBLE_MERGE	
+		--(iCommandIndexInRssFile[iCurrentCommandListInMapping]);
+		--iCommandIndex;
+#endif
+		}
+	
+#ifdef SYMBIAN_SSM_FLEXIBLE_MERGE
+	if (inProgress == EFalse || iCommandIndex == 0) // list preparation complete
+#else
+	if (iCommandIndex == 0) // list preparation complete
+#endif
+		{
+		ResetReadyForNextPrepare();
+		iCommandListReady = ETrue;
+		}
+	}
+
+void CSsmCommandListResourceReaderImpl::CPreparer::AddCommandToListL(TSsmCommandType aType, RResourceReader& aCommandReader, TInt aConditionalInfoResourceId)
+	{
+	// construct command from resource and add to list
+	CSsmCommandBase* cmd = NULL;
+
+	switch (aType)
+		{
+	case ESsmCmdPublishSwp:
+			{
+#ifdef SYMBIAN_SSM_FLEXIBLE_MERGE
+			TSsmCommandParameters params(aCommandReader, iMappingArray[iCurrentCommandListInMapping].iResourceFile, aConditionalInfoResourceId, iSwpChange);
+#else
+			TSsmCommandParameters params(aCommandReader, iMapping.iResourceFile, aConditionalInfoResourceId, iSwpChange);
+#endif
+			cmd = SsmCommandFactory::ConstructCommandFromResourceLC(aType, params);
+			break;
+			}
+	case ESsmCmdPublishSystemState:
+			{
+#ifdef SYMBIAN_SSM_FLEXIBLE_MERGE
+			TSsmCommandParameters params(aCommandReader, iMappingArray[iCurrentCommandListInMapping].iResourceFile, aConditionalInfoResourceId, iState);
+#else
+			TSsmCommandParameters params(aCommandReader, iMapping.iResourceFile, aConditionalInfoResourceId, iState);
+#endif
+			cmd = SsmCommandFactory::ConstructCommandFromResourceLC(aType, params);
+			break;
+			}
+	default:
+			{
+#ifdef SYMBIAN_SSM_FLEXIBLE_MERGE
+			TSsmCommandParameters params(aCommandReader, iMappingArray[iCurrentCommandListInMapping].iResourceFile, aConditionalInfoResourceId);
+#else
+			TSsmCommandParameters params(aCommandReader, iMapping.iResourceFile, aConditionalInfoResourceId);
+#endif
+			cmd = SsmCommandFactory::ConstructCommandFromResourceLC(aType, params);
+			break;
+			}
+		}
+#ifdef SYMBIAN_SSM_FLEXIBLE_MERGE
+	// Load the resource file if there is conditional information
+	if( cmd && cmd->ConditionalInformation() != 0 )
+		{
+		//Only if there is conditional information, we will set the command's resource filename
+		cmd->SetCommandResourceFileNameL(iResourcePool.FileNameForResourceFileL(iMappingArray[iCurrentCommandListInMapping].iResourceFile));
+		}
+#endif
+	//In the case of flexible merge the commands are appended in the commandlist based on priority. 
+	iCommandList->AppendL(cmd);
+	CleanupStack::Pop(cmd);
+	}
+
+