// 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"
#ifdef __WINS__
#include <u32hal.h>
//Literal to be appended with the main folder path to get the extended folder path
_LIT(KExtendedCommandListPath, "_ext\\");
//Used for checking the presence of keyword for using extended folder in epoc.ini
static TBool IsExtendedFolderDisabled()
{
TBool isMinimalBootDisable = EFalse;
//If the keyword "MINIMALSTART" is found in epoc.ini then only commands from main folder are
//executed else commands from both main and extended folder are executed.
UserSvr::HalFunction(EHalGroupEmulator, EEmulatorHalBoolProperty, (TAny*)"MINIMALSTART", &isMinimalBootDisable);
return isMinimalBootDisable;
}
#endif // __WINS__
#endif //SYMBIAN_SSM_FLEXIBLE_MERGE
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 %04x 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)
#if defined(SYMBIAN_SSM_FLEXIBLE_MERGE) && defined(__WINS__)
, iExtendedEntryIndex(0)
#endif //SYMBIAN_SSM_FLEXIBLE_MERGE && __WINS__
{
CActiveScheduler::Add(this);
}
CSsmCommandListResourceReaderImpl::CInitialiser::~CInitialiser()
{
Cancel();
ResetToUninitialisedState();
iPath.Close();
#ifdef SYMBIAN_SSM_FLEXIBLE_MERGE
iSystemDrivePath.Close();
#ifdef __WINS__
iExtendedPath.Close();
#endif //__WINS__
#endif
}
void CSsmCommandListResourceReaderImpl::CInitialiser::ResetToUninitialisedState()
{
delete iResourceFileEntries;
iResourceFileEntries = NULL;
iEntryIndex = 0;
iResourcePool.Reset();
iAction = EIdle;
#ifdef SYMBIAN_SSM_FLEXIBLE_MERGE
delete iRssFileEntriesInSysDrive;
iRssFileEntriesInSysDrive = NULL;
#ifdef __WINS__
delete iExtendedResourceFileEntries;
iExtendedResourceFileEntries = NULL;
#endif //__WINS__
#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;
#ifdef __WINS__
case EInitialiseExtFolderStep:
DoInitialiseExtFolderStepL();
break;
#endif //__WINS__
#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
#ifdef __WINS__
if(!IsExtendedFolderDisabled())
{
TFileName extPath(iPath);
extPath.Replace(iPath.Length() - 1, 1, KExtendedCommandListPath);
iExtendedPath.CreateL(extPath);
DEBUGPRINT2(_L("Extended list path is %S"), &extPath);
extPath.Append(KStar);
const TInt extErr = (iFs.GetDir(extPath, TUidType(KUidResourceFile, TUid::Uid(KUidSsmCommandListResourceFile)), ESortNone, iExtendedResourceFileEntries));
if (KErrNone == extErr)
{
iExtendedEntryIndex = iExtendedResourceFileEntries->Count();
DEBUGPRINT2(_L("Number of resource files in extended folder : %d"), iExtendedEntryIndex);
}
}
#endif //__WINS__
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
{
iAction = EIdle;
delete iRssFileEntriesInSysDrive;
iRssFileEntriesInSysDrive = NULL;
#ifdef __WINS__
if(!IsExtendedFolderDisabled())
{
//Initialise the command list from extended list only if it is enabled
iAction = EInitialiseExtFolderStep;
}
#endif //__WINS__
}
}
#ifdef __WINS__
void CSsmCommandListResourceReaderImpl::CInitialiser::DoInitialiseExtFolderStepL()
{
//Append the file names from the extended folder only if it is enabled
if (iExtendedEntryIndex--)
{
TFileName filename(iExtendedPath);
filename.Append((*iExtendedResourceFileEntries)[iExtendedEntryIndex].iName);
CResourceFile* const resourceFile = OpenResourceFileL(filename);
ParseFileL(resourceFile);
}
else
{
// initialisation complete
iAction = EIdle;
delete iExtendedResourceFileEntries;
iExtendedResourceFileEntries = NULL;
}
}
#endif //__WINS__
#endif //SYMBIAN_SSM_FLEXIBLE_MERGE
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));
}
}
#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();
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);
}