aknlayoutcompiler/src/MLCompCdl2InstO.cpp
changeset 0 f58d6ec98e88
child 1 b700e12870ca
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/aknlayoutcompiler/src/MLCompCdl2InstO.cpp	Thu Dec 17 09:14:18 2009 +0200
@@ -0,0 +1,2016 @@
+/*
+* Copyright (c) 2002-2008 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:  
+*
+*/
+
+
+// disable "identifier was truncated to '255' characters in the browser information" warning
+#pragma warning (disable:4786)
+
+// disable "decorated name length exceeded, name was truncated" warning	
+#pragma warning (disable:4503)
+
+#include "MLCompDataParse.h"
+#include "MLCompCdl2InstO.h"
+#include "ZoomLevelNames.h"
+#include "LayoutCompilerErr.h"
+#include "LayoutParse.h"
+#include "CppWriter.h"
+#include "MLCompData2Cdl.h"
+#include "LayCdl2InstO.h" // for common classes
+#include "MLAttributesParse.h"
+#include "MLAttributes.h"
+#include "CodeGenConsts.h"
+#include "UsefulDefinitions.h"
+
+#include <akndef.hrh>
+
+#include <fstream>
+#include <algorithm>
+#include <iostream>
+#include <numeric> // accumulate
+
+using namespace std;
+using namespace CdlCompilerToolkit;
+
+//
+// defines
+//
+
+#define AKNLAYOUT_DEFINE_BYTECODE(name,byte) const char name = char(byte);
+#include "AknLayoutByteCodes.h"
+
+typedef LayoutProcessArgsErr<MLCompDataCdlInstanceOpt> MLCompDataCdlInstanceOptArgsErr;
+
+
+//
+// constants
+//
+
+const string KDefinitionNotDefined("Layout not defined, this API must not be called for this instance");
+const string KDefinitionNotSet("Layout definition not found");
+extern string KMultiLine;
+const string KSpace = " ";
+const string KComma = ",";
+const string KTheWordBlank("blank");
+const string KParentRelativeMarker("Pp");
+const string KCellNameJustification("J");
+const string KCompDataFileNameSuffix("compData");
+const string KAttributesFileNameSuffix("attributes");
+
+// this is the addressable area for each instance, as the lookup table is 16bit
+const int KAddressableBytecodedData = 0xFFFF;
+
+/**
+*  SCompDataImplFunc
+*  This class represents a layout data decompression function local to a layout instance.
+*  These functions will call the corresponding DLL wide function for decompression.
+*/
+struct SCompDataImplFunc
+	{
+	enum TFuncType
+		{ 
+		EWindowLine, 
+		ETextLine,
+		ETableLimits,
+		EWindowTable, 
+		ETextTable,
+		ELineParamLimits,
+		ETableParamLimits,
+		EGenericComponentType,
+		EGenericParamLimits,
+		EGenericWindowComponent,
+		EGenericTextComponent
+		};
+	TFuncType iType;
+	CCdlTkApiParams iParams;
+	string iDefn;
+	string iPtrRef;
+
+	SCompDataImplFunc(TFuncType aType, string aDefn, string aPtrRef, CCdlTkApiParams& aParams)
+		: 
+		iType(aType), 
+		iDefn(aDefn), 
+		iPtrRef(aPtrRef),
+		iParams(aParams)
+		{
+			
+		}
+
+	SCompDataImplFunc(TFuncType aType, string aDefn, string aPtrRef)
+		: 
+		iType(aType), 
+		iDefn(aDefn), 
+		iPtrRef(aPtrRef)
+		{
+			
+		}
+
+	bool IsSimilar(TFuncType aType, CCdlTkApiParams& aParams)
+		{
+		if(iType != aType) 
+			return false;
+		int size = iParams.size();
+		if(size != aParams.size())
+			return false;
+		for(int ii = 0; ii < size; ii++)
+			{
+			CCdlTkApiParam& thisParam = iParams[ii];
+			CCdlTkApiParam& otherParam = aParams[ii];
+			if(thisParam.Name() != otherParam.Name())
+				return false;
+			if(thisParam.Type() != otherParam.Type())
+				return false;
+			// don't compare the default value, as we're not interested in that for the implementation.
+			}
+		return true;
+		}
+	};
+
+
+/**
+*  CAllCompDataFuncs
+*  This represents a collection of all the SCompDataImplFunc objects that a layout instance may need
+*/
+class CAllCompDataFuncs : public vector<SCompDataImplFunc>
+	{
+public:
+	CAllCompDataFuncs();
+
+private:
+	void AddFunc(SCompDataImplFunc::TFuncType aType, CCdlTkApiParams& aParams, const string& aReturn, const string& aFuncName, bool aAppendAbbreviation);
+	void AddParamsToFunc(CCdlTkApiParams& aParams, string& aDefn, string& aBody);
+	void AddParamToFunc(string aFiller, string aParamName, string& aDefn, string& aBody);
+	};
+
+
+
+/**
+*  gTheFuncs
+*  This is a collection of all SCompDataImplFunc objects that a layout instance needs, initialised
+*  so that there are up to four integer parameters per API type.
+*/
+CAllCompDataFuncs gTheFuncs;
+
+//
+// CAllCompDataFuncs
+//
+
+CAllCompDataFuncs::CAllCompDataFuncs()
+	{
+	// need to generate all combinations of parameters
+	vector<string> paramNames;
+	paramNames.push_back(KParamOptionIndex);
+	paramNames.push_back(KParamColIndex);
+	paramNames.push_back(KParamRowIndex);
+
+	// all cominations of option, row, and column are possible, in any order
+	typedef vector<int> Seq;
+	Seq pattern;
+	set< Seq > subPatterns;
+
+	// for each of the available positions, there could be any available value, or it could be empty
+	const int numPlaces = paramNames.size();
+	for(int jj = 0; jj < numPlaces; jj++)
+		pattern.push_back(jj);
+
+	// for each permutation, copy all the possible positions
+	// into a separate set, which hence will be filled with the unique permutations
+	do
+		{
+		int numMasks = (1 << numPlaces); // eg for 3 places there are 8 masks
+		for(int mask = 0; mask < numMasks; mask++)
+			{
+			Seq subPattern;
+			int bit = 0;
+			// count down the bits
+			for(int bitCount = mask; bitCount != 0; bitCount >>= 1)
+				{
+				if(mask & (1 << bit))
+					subPattern.push_back(pattern[bit]);
+				bit++;
+				}
+			subPatterns.insert(subPattern);
+			}
+		}
+	while(next_permutation(pattern.begin(), pattern.end()));
+
+	for(set< Seq >::iterator pPattern = subPatterns.begin(); pPattern != subPatterns.end(); ++pPattern)
+		{
+		CCdlTkApiParams params;
+		for(Seq::iterator pParam = pPattern->begin(); pParam != pPattern->end(); ++pParam)
+			{
+			int& param = (*pParam);
+			string name = paramNames[param];
+			params.push_back(CCdlTkApiParam(KTypeInt, name));
+			}
+		AddFunc(SCompDataImplFunc::EWindowLine, params, KTypeWindowComponentLayout, KFuncWindowLine, true);
+		AddFunc(SCompDataImplFunc::ETextLine, params, KTypeTextComponentLayout, KFuncTextLine, true);
+
+		params.insert(params.begin(), CCdlTkApiParam(KTypeInt, KParamLineIndex));
+		AddFunc(SCompDataImplFunc::EWindowTable, params, KTypeWindowComponentLayout, KFuncWindowTable, true);
+		AddFunc(SCompDataImplFunc::ETextTable, params, KTypeTextComponentLayout, KFuncTextTable, true);
+		}
+
+	for(int ii = 0; ii < 2; ii++)
+		{
+		CCdlTkApiParams params;
+		if(ii)
+			{
+			params.push_back(CCdlTkApiParam(KTypeInt, KParamOptionIndex));
+			}
+		AddFunc(SCompDataImplFunc::ELineParamLimits, params, KTypeLayoutScalableParameterLimits, KFuncParamLimits, true);
+		params.insert(params.begin(), CCdlTkApiParam(KTypeInt, KParamLineIndex));
+		AddFunc(SCompDataImplFunc::ETableParamLimits, params, KTypeLayoutScalableParameterLimits, KFuncParamLimitsTable, true);
+		}
+
+	SCompDataImplFunc limits(
+		SCompDataImplFunc::ETableLimits, 
+		KTypeLayoutScalableTableLimits + " Limits() { return AknLayoutScalableDecode::TableLimits(KDataLookup); }",
+		"&Limits");
+	push_back(limits);
+
+	// finally, the generic APIs
+	CCdlTkApiParams params;
+	params.push_back(CCdlTkApiParam(KTypeInt, KParamComponentId));
+	AddFunc(SCompDataImplFunc::EGenericComponentType, params, KTypeLayoutScalableComponentType, KFuncGetComponentTypeById, false);
+
+	// param limits needs the variety index
+	params.push_back(CCdlTkApiParam(KTypeInt, KParamOptionIndex));
+	AddFunc(SCompDataImplFunc::EGenericParamLimits, params, KTypeLayoutScalableParameterLimits, KFuncGetParamLimitsById, false);
+
+	// and getting the component by id requires all the params
+	params.push_back(CCdlTkApiParam(KTypeInt, KParamColIndex));
+	params.push_back(CCdlTkApiParam(KTypeInt, KParamRowIndex));
+	AddFunc(SCompDataImplFunc::EGenericWindowComponent, params, KTypeWindowComponentLayout, KFuncGetWindowComponentById, false);
+	AddFunc(SCompDataImplFunc::EGenericTextComponent, params, KTypeTextComponentLayout, KFuncGetTextComponentById, false);
+	}
+
+void CAllCompDataFuncs::AddFunc(SCompDataImplFunc::TFuncType aType, CCdlTkApiParams& aParams, const string& aReturn, const string& aFuncName, bool aAppendAbbreviation)
+	{
+	// create a function of this form:
+	//TAknWindowComponentLayout WindowTable$NUM$PARENT($PARAMS_TYPES_AND_NAMES)
+	//	{
+	//	return AknLayoutScalableDecode::WindowLine$NUM$PARENT(&KImplData, $PARAM_NAMES);
+	//  }
+	string funcName = aFuncName;
+	if(aAppendAbbreviation)
+		for(CCdlTkApiParams::iterator pParam = aParams.begin(); pParam != aParams.end(); ++pParam)
+			funcName += pParam->Name().substr(1, 1); // append the first character after the "a"
+
+	string defn = aReturn + " " + funcName + "(";
+	string body = string(") { return AknLayoutScalableDecode::") + funcName + "(&KImplData";
+	AddParamsToFunc(aParams, defn, body);
+	defn += body + "); }";
+
+	string ptrRef = string("&") + funcName;
+
+	SCompDataImplFunc func(aType, defn, ptrRef, aParams);
+	push_back(func);
+	}
+
+void CAllCompDataFuncs::AddParamsToFunc(CCdlTkApiParams& aParams, string& aDefn, string& aBody)
+	{
+	string filler = "";
+	for(CCdlTkApiParams::iterator pParam = aParams.begin(); pParam != aParams.end(); ++pParam)
+		{
+		AddParamToFunc(filler, pParam->Name(), aDefn, aBody);
+		filler = KComma + KSpace;
+		}
+	}
+
+void CAllCompDataFuncs::AddParamToFunc(string aFiller, string aParamName, string& aDefn, string& aBody)
+	{
+	aDefn += aFiller + string(KTypeInt) + KSpace + aParamName;
+	aBody += KComma + KSpace + aParamName;
+	}
+
+
+//
+// CMLCompDataInstOptImpl
+//
+
+class CMLCompDataInstOptImpl
+	{
+public:
+	CMLCompDataInstOptImpl(CCdlTkImplementation* aImpl);
+	virtual ~CMLCompDataInstOptImpl();
+public:
+	CCdlTkImplementation* iImpl;
+	int iByteCodeIndex;
+	string iComment;
+	string iName;
+	vector<char> iBytes;
+	bool iIsRedirectedToExactCopy;
+	};
+
+CMLCompDataInstOptImpl::CMLCompDataInstOptImpl(CCdlTkImplementation* aImpl)
+	:
+	iImpl(aImpl),
+	iIsRedirectedToExactCopy(false)
+	{
+	}
+
+CMLCompDataInstOptImpl::~CMLCompDataInstOptImpl()
+	{
+	}
+
+//
+// CMLCompDataLineInstOptImpl
+//
+
+class CMLCompDataLineInstOptImpl : public CMLCompDataInstOptImpl
+	{
+public:
+	CMLCompDataLineInstOptImpl(TMLCompDataLine* aLine, CCdlTkImplementation* aImpl);
+	virtual ~CMLCompDataLineInstOptImpl();
+public:
+	TMLCompDataLine* iLine;
+	};
+
+CMLCompDataLineInstOptImpl::CMLCompDataLineInstOptImpl(TMLCompDataLine* aLine, CCdlTkImplementation* aImpl)
+	: 
+	CMLCompDataInstOptImpl(aImpl),
+	iLine(aLine)
+	{
+	}
+
+CMLCompDataLineInstOptImpl::~CMLCompDataLineInstOptImpl()
+	{
+	}
+
+
+//
+// CMLCompDataSubTableInstOptImpl
+//
+
+class CMLCompDataSubTableInstOptImpl : public CMLCompDataInstOptImpl
+	{
+public:
+	CMLCompDataSubTableInstOptImpl(
+		TMLCompDataTable* aTable,
+		TMLCompDataTable::TMLCompDataSubTable* aSubTable, 
+		CCdlTkImplementation* aImpl);
+	virtual ~CMLCompDataSubTableInstOptImpl();
+public:
+	TMLCompDataTable* iTable;
+	TMLCompDataTable::TMLCompDataSubTable* iSubTable;
+	};
+
+CMLCompDataSubTableInstOptImpl::CMLCompDataSubTableInstOptImpl(
+	TMLCompDataTable* aTable,
+	TMLCompDataTable::TMLCompDataSubTable* aSubTable, 
+	CCdlTkImplementation* aImpl)
+	:
+	iTable(aTable),
+	CMLCompDataInstOptImpl(aImpl),
+	iSubTable(aSubTable)
+	{
+	}
+
+CMLCompDataSubTableInstOptImpl::~CMLCompDataSubTableInstOptImpl()
+	{
+	}
+
+
+//
+// CMLCompDataInstOpt
+//
+
+class CMLCompDataInstOpt
+	{
+public:
+	CMLCompDataInstOpt(MLCompDataCdlInstanceOpt& aInstances, TMLCompData* aLayout, const string& aInstName, const string& aZoomName, int aZoomLevel, bool aAllParams, bool aNonCompleteInstance);
+	~CMLCompDataInstOpt();
+
+	void Process(const string& aFirstInstanceName);
+	void WriteInstance();
+
+	CCdlTkInstance& Inst() const { return *iInstance; }
+	string Name() const { return iName; }
+	string ZoomName() const { return iZoomName; }
+
+private:
+	typedef vector<int> ParamLimitVarieties;
+	typedef vector<ParamLimitVarieties> ParamLimits;
+	typedef map<int, int> IndexMap;
+
+private:
+	void ProcessLines(TMLCompDataTable& aTable);
+	void ProcessTables(TMLCompDataTable& aTable);
+	void ProcessLine(TMLCompDataLine& aLine);
+	void ProcessLineApi(TMLCompDataLine& aLine, CCdlTkImplementation& aImpl);
+	void UpdateBaseOffset();
+	void UpdateLine(CMLCompDataInstOptImpl& aImpl, int& aByteCodeSizeDelta);
+	void UpdateLineImpls();
+	void UpdateLineImplDefn(CMLCompDataInstOptImpl& aImpl);
+	void UpdateTableInstance(TMLCompDataTable& aTable, TMLCompDataTable::TMLCompDataSubTable& aSub, CMLCompDataInstOptImpl* aImpl);
+
+	void SetNewLineData(CMLCompDataLineInstOptImpl& aImpl);
+	void SetNewLineParamData(CMLCompDataLineInstOptImpl& aImpl, IndexMap& aIndexMap, int aTotalMax, int aNumVarieties);
+	void OptimizeNewLineData(CMLCompDataLineInstOptImpl& aImpl, IndexMap& aIndexMap, vector<char>& aTempBytes, const vector<string>& aOutputOrder, bool aMirrored, int aTotalMax, int aNumVarieties);
+	void OptimizeNewLineCellData(IndexMap& aIndexMap, vector<char>& aTempBytes, TMLCompDataValues& aValues, unsigned int& aNextCell, int aTotalParams, int aNumVarieties, ParamLimitVarieties& aParamLimitVarieties, string cellName, bool aMirrorJustification);
+	void EncodeNewLineCellData(IndexMap& aIndexMap, vector<char>& aTempBytes, vector<string>& aValuesToEncode, unsigned int& aNextCell, int aTotalMax, bool aOptimizeVarieties, bool aOptimizeCalcs);
+
+	bool HasApi(const string& aName);
+	CCdlTkImplementation& FindImp(const string& aName);
+	CMLCompDataInstOptImpl* FindSimilarImpl(const CMLCompDataInstOptImpls& aImpls, const CCdlTkImplementation& aImpl);
+	string DefinitionString(int aByteCodeIndex, const string& aApiName);
+	bool CheckByteCodeIndexInRange(int aByteCodeIndex);
+
+	void SetGenericFunc(CMLCompDataInstOptImpl& aImpl, SCompDataImplFunc::TFuncType aType);
+	void SetLineFunc(CMLCompDataLineInstOptImpl& aImpl);
+	void SetSubTableFunc(CMLCompDataSubTableInstOptImpl& aImpl);
+	void SetParamLimits(CMLCompDataLineInstOptImpl& aImpl);
+
+	void ValidateRequiredParams(string aApiName, CCdlTkApiParams& aParams, bool aOption, bool aColumn, bool aRow);
+	void CountApiParams(CCdlTkImplementation& aApi, int& aParams);
+	SCompDataImplFunc& AddImplFunc(SCompDataImplFunc::TFuncType aType);
+	SCompDataImplFunc& AddImplFunc(SCompDataImplFunc::TFuncType aType, CCdlTkApiParams& aParams);
+
+	void SetGenericAPI(SCompDataImplFunc::TFuncType aType, const string& aName);
+	void SetExtraCpp(const string& aFirstInstanceName);
+	void OutputStats();
+
+	void AddTableToInstance(TMLCompDataTable& aTable, TMLCompDataTable::TMLCompDataSubTable& aSub, int aTableNum);
+	void UpdateTables(TMLCompDataTable& aTable);
+	void AddTableParamLimitsImpl(const string& aApiName, int aByteCodeIndex, SCompDataImplFunc::TFuncType aType, bool aNeedsOptions);
+	void UpdateTableParamLimitsImpl(const string& aApiName, int aByteCodeIndex);
+	void AddTableLimitsImpl(const string& aApiName, TMLCompDataTable::TMLCompDataSubTable& aSubTable);
+	void AddTableLimitsImplDefn(TMLCompDataTable::TMLCompDataSubTable& aSubTable, CCdlTkImplementation& aImpl);
+	void AddTableImpl(const string& aApiName, TMLCompDataTable& aTable, TMLCompDataTable::TMLCompDataSubTable& aSub);
+	void AddParamLimits(TMLCompDataLine& aLine, bool aNeedsOptions);
+	void UpdateParamLimits(const string& apiName);
+	void SetDummyTableData(TMLCompDataTable& aTable, TMLCompDataTable::TMLCompDataSubTable& aSubTable, CMLCompDataInstOptImpl& aImpl);
+	void UpdateTableData(TMLCompDataTable& aTable, TMLCompDataTable::TMLCompDataSubTable& aSubTable, CMLCompDataInstOptImpl& aImpl);
+	void EncodeValue(vector<char>& aBytes, string aValue);
+	void EncodeValue(vector<char>& aBytes, int aValue);
+	void EncodeParentRelativeValue(vector<char>& aBytes, int aValue);
+	void MirrorParamName(string& aParamName);
+
+private:
+	MLCompDataCdlInstanceOpt& iInstances;
+	TMLCompData* iLayout;
+	string iName;
+	string iZoomName;
+	CCdlTkInterface& iInterface;
+	CCdlTkInstance* iInstance; // not owned
+	CMLCompDataInstOptImpls iImpls;
+	CMLCompDataInstOptImpls iTableImpls;
+	typedef vector<SCompDataImplFunc*> CImplFuncs;
+	CImplFuncs iFuncs;
+	int iZoomLevel;
+	bool iAllParams;
+	int iBaseOffset; // offset from the start of the main data table to the start of this instance's data
+	};
+
+CMLCompDataInstOpt::CMLCompDataInstOpt(MLCompDataCdlInstanceOpt& aInstances, TMLCompData* aLayout, const string& aInstName, const string& aZoomName, int aZoomLevel, bool aAllParams, bool aNonCompleteInstance)
+	: 
+	iInstances(aInstances), 
+	iLayout(aLayout),
+	iName(aInstName), 
+	iZoomName(aZoomName), 
+	iZoomLevel(aZoomLevel),
+	iInterface(iInstances.Interface()),
+	iAllParams(aAllParams),
+	iBaseOffset(0)
+	{
+	string zoomInstName = aInstName;
+	if(aZoomName.length() > 0)
+		zoomInstName += "_" + aZoomName;
+
+	iInstance = new CCdlTkInstance(iInterface);
+	iInstance->SetName(zoomInstName);
+
+	CCdlTkImplementations& impl = iInstance->Impl();
+	for (CCdlTkImplementations::iterator pImpl = impl.begin(); pImpl != impl.end(); ++pImpl)
+		{
+		const CCdlTkInterface& iface = (*pImpl)->Instance().Interface();
+		const CCdlTkApi& api = (*pImpl)->Api();
+		if(aLayout->iIsBaseInstance)
+			{
+			// for a base instance, need to set a default implementation
+			// even for missing data
+			(*pImpl)->SetDefinition(CdlTkUtil::ShortToHexString(0) + ",\t// " + KDefinitionNotDefined);
+			
+			// preliminary implementation of "blank" implementation. cdl engine searches to ensure that
+			// all implementations are not NULL. So this will satisfy that test. However, if any of the 
+			// methods are called, there will be an access violation, which will cause a panic
+			// this will be a successful guide to implementers not to call the API when the wrong layout
+			// pack is installed.
+			string definition = "(" + iface.NamespaceName() + "::" + api.PointerType() + ")((void*)4), // LAYOUT NOT DEFINED FOR THIS INSTANCE";
+			(*pImpl)->SetPointerReference(definition); 
+			}
+        else if(aNonCompleteInstance)
+            {
+			// for a base instance, need to set a default implementation
+			// even for missing data
+			(*pImpl)->SetDefinition(CdlTkUtil::ShortToHexString(0) + ",\t// " + KDefinitionNotDefined);
+
+            // but we need the pointer to be null so that CdlEngine falls through the layer below
+			string definition =  "0, // " + iface.NamespaceName() + "::" + api.PointerType();
+			(*pImpl)->SetPointerReference(definition); 
+            }
+        else
+			{
+			// Initially set definition that will not compile in the resulting code.
+			// This will alert the programmer to missing layout data.
+			(*pImpl)->SetDefinition(KDefinitionNotSet);
+			}
+		}
+	}
+
+CMLCompDataInstOpt::~CMLCompDataInstOpt()
+	{
+	delete iInstance;
+	for (CMLCompDataInstOptImpls::iterator pImpl = iImpls.begin(); pImpl != iImpls.end(); ++pImpl)
+		delete *pImpl;
+	for (pImpl = iTableImpls.begin(); pImpl != iTableImpls.end(); ++pImpl)
+		delete *pImpl;
+	}
+
+void CMLCompDataInstOpt::Process(const string& aFirstInstName)
+	{
+	iLayout->Compile();
+
+	for (TMLCompData::iterator pTab = iLayout->begin(); pTab != iLayout->end(); ++pTab)
+		{
+		ProcessLines(**pTab);
+		}
+
+	for (pTab = iLayout->begin(); pTab != iLayout->end(); ++pTab)
+		{
+		ProcessTables(**pTab);
+		}
+
+	// update the base offset to include all the data added, including reserving space for the tables
+	UpdateBaseOffset();
+
+	// with the correct base offset, the definitions can be updated
+	UpdateLineImpls();
+
+	for (pTab = iLayout->begin(); pTab != iLayout->end(); ++pTab)
+		{
+		// now that the rest of the data is stable, we can add the tables at the end
+		UpdateTables(**pTab);
+		}
+
+	SetGenericAPI(SCompDataImplFunc::EGenericComponentType, KFuncGetComponentTypeById);
+	SetGenericAPI(SCompDataImplFunc::EGenericParamLimits, KFuncGetParamLimitsById);
+	SetGenericAPI(SCompDataImplFunc::EGenericWindowComponent, KFuncGetWindowComponentById);
+	SetGenericAPI(SCompDataImplFunc::EGenericTextComponent, KFuncGetTextComponentById);
+	
+	SetExtraCpp(aFirstInstName);
+	OutputStats();
+	}
+
+void CMLCompDataInstOpt::WriteInstance()
+	{
+	CCdlTkWriteInstance writer(*iInstance);
+	writer.Process();
+	}
+
+void CMLCompDataInstOpt::ProcessLines(TMLCompDataTable& aTable)
+	{
+	for (TMLCompDataTable::iterator pLine = aTable.begin(); pLine != aTable.end(); ++pLine)
+		{
+		ProcessLine(**pLine);
+		}
+	}
+
+void CMLCompDataInstOpt::ProcessTables(TMLCompDataTable& aTable)
+	{
+	int line = 0;
+	for (TMLCompDataTable::iterator pLine = aTable.begin(); pLine != aTable.end(); ++pLine)
+		{
+		for (TMLCompDataTable::TMLCompDataSubTables::const_iterator pSub = aTable.iSubTables.begin(); pSub != aTable.iSubTables.end(); ++pSub)
+			{
+			TMLCompDataTable::TMLCompDataSubTable& sub = **pSub;
+			int last = *(sub.rbegin());
+			if(line == last)
+				AddTableToInstance(aTable, sub, 0);
+			}
+		line++;
+		}
+	}
+
+void CMLCompDataInstOpt::ProcessLine(TMLCompDataLine& aLine)
+	{
+	string apiName = MLCompDataToCdl::LineApiName(aLine);
+	if (!HasApi(apiName))
+		return;
+
+	ProcessLineApi(aLine, FindImp(apiName));
+	}
+
+void CMLCompDataInstOpt::ProcessLineApi(TMLCompDataLine& aLine, CCdlTkImplementation& aImpl)
+	{
+	string lineName = MLCompDataToCdl::LineApiName(aLine);
+
+	CMLCompDataLineInstOptImpl* newImpl = new CMLCompDataLineInstOptImpl(&aLine, &aImpl);
+	iImpls.push_back(newImpl);
+
+	// always set the new line data
+	SetNewLineData(*newImpl);
+
+	// if we can find the new line data in the aggregated data, point to that instead
+	int foundIndex = iInstances.FindSimilarBytes(newImpl, iBaseOffset);
+	if(foundIndex >= 0)
+		{
+		newImpl->iByteCodeIndex = foundIndex;
+		newImpl->iIsRedirectedToExactCopy = true;
+		}
+	else
+		{
+		iInstances.AddImpl(newImpl);
+		}
+
+	SetLineFunc(*newImpl);
+
+	// only add parameter limits if the line is not simple
+	// and we must add the param limits after the actual impl, so that we can find it!
+	bool needsParamLimits = aLine.NeedsOptions() || aLine.NeedsCols() || aLine.NeedsRows();
+	if(needsParamLimits)
+		{
+		AddParamLimits(aLine, aLine.NeedsOptions());
+		}
+	}
+
+void CMLCompDataInstOpt::UpdateBaseOffset()
+	{
+	// have to account for this instance's tables
+	int tablesSize(0);
+	for(CMLCompDataInstOptImpls::iterator pTableImpl = iTableImpls.begin(); pTableImpl != iTableImpls.end(); ++pTableImpl)
+		{
+		CMLCompDataInstOptImpl* impl = *pTableImpl;
+		tablesSize += impl->iBytes.size();
+		}
+
+	int origByteStreamSize = iInstances.ByteStreamSize() + tablesSize;
+
+	// repeat until base offset stabilizes
+	iBaseOffset = max(0, origByteStreamSize - KAddressableBytecodedData);
+	int newBaseOffset = iBaseOffset;
+	int byteCodeSizeDelta(0);
+	do
+		{
+		iBaseOffset = newBaseOffset;
+		for(CMLCompDataInstOptImpls::iterator pImpl = iImpls.begin(); pImpl != iImpls.end(); ++pImpl)
+			UpdateLine(**pImpl, byteCodeSizeDelta);
+		newBaseOffset = max(0, origByteStreamSize + byteCodeSizeDelta - KAddressableBytecodedData);
+		}
+	while(iBaseOffset != newBaseOffset);
+	}
+
+void CMLCompDataInstOpt::UpdateLine(CMLCompDataInstOptImpl& aImpl, int& aByteCodeSizeDelta)
+	{
+	if(aImpl.iIsRedirectedToExactCopy && aImpl.iByteCodeIndex < iBaseOffset)
+		{
+		// when we encoded the impls, we found a match in an area which now
+		// turns out to be before the base offset (i.e. outside the addressable range).
+
+		// first of all check in case we've already made another copy close by
+		int foundIndex = iInstances.FindSimilarBytes(&aImpl, iBaseOffset);
+		if(foundIndex >= 0)
+			{
+			aImpl.iByteCodeIndex = foundIndex;
+			}
+		else
+			{
+			// add its bytecodes to the end
+			aImpl.iIsRedirectedToExactCopy = false;
+			iInstances.AddImpl(&aImpl);
+			aByteCodeSizeDelta += aImpl.iBytes.size();
+			}
+		}
+	}
+
+
+void CMLCompDataInstOpt::UpdateLineImpls()
+	{
+	for(CMLCompDataInstOptImpls::iterator pImpl = iImpls.begin(); pImpl != iImpls.end(); ++pImpl)
+		UpdateLineImplDefn(**pImpl);
+	}
+
+void CMLCompDataInstOpt::UpdateLineImplDefn(CMLCompDataInstOptImpl& aImpl)
+	{
+	if(!CheckByteCodeIndexInRange(aImpl.iByteCodeIndex))
+		throw GeneralErr(aImpl.iName + " in interface " + iInterface.FileName());
+	// the base offset has been updated, so all definitions must be refreshed
+	int adjustedIndex = aImpl.iByteCodeIndex - iBaseOffset;
+	aImpl.iImpl->SetDefinition(DefinitionString(aImpl.iByteCodeIndex, aImpl.iName));
+	UpdateParamLimits(aImpl.iName); 
+	}
+
+void CMLCompDataInstOpt::UpdateTables(TMLCompDataTable& aTable)
+	{
+	// regenerate the byte code indices, in case they have changed
+	int line = 0;
+	for (TMLCompDataTable::iterator pLine = aTable.begin(); pLine != aTable.end(); ++pLine)
+		{
+		for (TMLCompDataTable::TMLCompDataSubTables::const_iterator pSub = aTable.iSubTables.begin(); pSub != aTable.iSubTables.end(); ++pSub)
+			{
+			TMLCompDataTable::TMLCompDataSubTable& sub = **pSub;
+			int last = *(sub.rbegin());
+			if(line == last)
+				{
+				string tableName = MLCompDataToCdl::SubTableApiName(sub);
+				CMLCompDataInstOptImpl* impl = FindSimilarImpl(iTableImpls, FindImp(tableName));
+				UpdateTableInstance(aTable, sub, impl);
+				}
+			}
+		line++;
+		}
+	}
+
+void CMLCompDataInstOpt::SetNewLineData(CMLCompDataLineInstOptImpl& aImpl)
+	{
+	aImpl.iBytes.clear();	
+
+	TMLCompDataLine& line = *aImpl.iLine;
+	aImpl.iComment = string("for line: ");
+	aImpl.iName = MLCompDataToCdl::LineApiName(line);
+
+	// handle mirroring order
+	bool mirrored = false;
+	if(line.iParentTable) // we know top table can't be mirrored
+		mirrored = line.iParentTable->iTables->iCanBeMirror;
+	const string* outputOrder =  mirrored ? 
+		KCompDataGraphicOutputOrderMirrored : KCompDataGraphicOutputOrder;
+	int outputSize = KCompDataGraphicOutputOrderSize;
+	if (line.iType == TMLCompDataLine::ETextComponent)
+		{
+		outputOrder = mirrored ? 
+			KCompDataTextOutputOrderMirrored : KCompDataTextOutputOrder;
+		outputSize = KCompDataTextOutputOrderSize;
+		}
+	vector<string> cellOrder(outputOrder, outputOrder + outputSize);
+
+	// we are currently storing variety as max allowed value, but it's a zero based index
+	int numVarieties = line.MaxVariety() + 1;
+
+	// we will be storing all of the rows and cols, even if the rows and cols limits are lower
+	int totalMaxCols = numVarieties * line.NumCols();
+	int totalMaxRows = numVarieties * line.NumRows();
+    int totalMax = totalMaxCols > totalMaxRows ? totalMaxCols : totalMaxRows;
+
+	// initialize the temporary bytestream, and the index map
+	vector<char> tempBytes;
+	IndexMap indexMap;
+
+	// fill in the temp byte stream and the index map for each cell
+	OptimizeNewLineData(aImpl, indexMap, tempBytes, cellOrder, mirrored, totalMax, numVarieties);
+
+	// encode the index map
+	SetNewLineParamData(aImpl, indexMap, totalMax, numVarieties);
+
+	// finally copy the temp byte stream onto the end of the real encoded byte stream
+	copy(tempBytes.begin(), tempBytes.end(), back_inserter(aImpl.iBytes));
+	}
+
+void CMLCompDataInstOpt::SetNewLineParamData(CMLCompDataLineInstOptImpl& aImpl, IndexMap& aIndexMap, int aTotalMax, int aNumVarieties)
+	{
+	// only set parameter data if the line is not simple
+	TMLCompDataLine& line = *aImpl.iLine;
+	
+	bool needsHeader = line.NeedsOptions() || line.NeedsCols() || line.NeedsRows();
+
+	int typeBitfield = line.iType << 1;
+	if(needsHeader)
+		{
+		typeBitfield |= 1;
+		}
+	
+	aImpl.iBytes.push_back(typeBitfield);
+
+	if(needsHeader)
+		{
+		// we can just dump the number of varieties, this will be used by the limits API
+		// and we can also them to calculate value indices within a cell when decoding
+		aImpl.iBytes.push_back(aNumVarieties);
+		}
+
+	//  count the number of cells that are complex
+	char numMultiValues = aIndexMap.size();
+	if(needsHeader)
+		{
+		aImpl.iBytes.push_back(numMultiValues);
+		}
+	else
+		{
+		// we didn't think we needed a header, so there should be no complex cells!
+		if (numMultiValues > 0)
+			throw GeneralErr("complex cells detected in simple line");
+		}
+
+	// for each complex cell, encode the bitfield and the count
+	for(IndexMap::iterator pIndex = aIndexMap.begin(); pIndex != aIndexMap.end(); ++pIndex)
+		{
+		int count = pIndex->first;
+		int index = pIndex->second;
+		EncodeValue(aImpl.iBytes, index);
+		EncodeValue(aImpl.iBytes, count);
+		}
+	}
+
+void CMLCompDataInstOpt::OptimizeNewLineData(
+	CMLCompDataLineInstOptImpl& aImpl, 
+	IndexMap& aIndexMap, 
+	vector<char>& aTempBytes,
+	const vector<string>& aOutputOrder,
+	bool aMirrored,
+	int aTotalMax, 
+	int aNumVarieties)
+	{
+	vector<ParamLimitVarieties> paramLimits;
+	TMLCompDataLine& line = *aImpl.iLine;
+
+	// start by extracting the row and column data. 
+	// we can optimize the stored format along with the rest of the data
+	// so no need to optimize it yet
+	for(int cell = 0; cell < 2; cell++)
+		{
+		string cellName = aOutputOrder[cell];
+		ParamLimitVarieties nextLimits;
+		TMLCompDataValues& values = line[cellName];
+		for(int varietyIndex = 0; varietyIndex < aNumVarieties; varietyIndex++)
+			{
+			TMLCompDataZoomLevels& zoomLevels = values[varietyIndex];
+			TMLCompDataCalcs* calcs = &(zoomLevels[iZoomLevel]);
+			if(!calcs->size())
+				calcs = &(zoomLevels[EAknUiZoomNormal]);
+			int value = CdlTkUtil::ParseInt((*calcs)[0]);
+			nextLimits.push_back(value);
+			}
+		paramLimits.push_back(nextLimits);
+		}
+
+	// calculate the number of values
+	bool needsHeader = line.NeedsOptions() || line.NeedsCols() || line.NeedsRows();
+	unsigned int nextCellFlag = 1;	// bit flag for the next cell, note it can get bigger than a char
+	for (cell = 0; cell < aOutputOrder.size(); cell++)
+		{
+		string cellName = aOutputOrder[cell];
+		TMLCompDataValues::TCompDataCellType type = TMLCompDataValues::Type(cellName);
+		if(!needsHeader && type == TMLCompDataValues::ECellTypeParamLimit)
+			{
+			// if we don't need header, then don't output the param limits values
+			// although we'll still use them internally
+			continue;
+			}
+
+		int paramLimitsIndex = TMLCompDataValues::Type(cellName) == TMLCompDataValues::ECellTypeCol ? 0 : 1; // if it's not a row or col, it doesn't matter what param limits are used.
+		TMLCompDataValues& values = line[cellName];
+		int numValues = 0;
+		if(type == TMLCompDataValues::ECellTypeCol || type == TMLCompDataValues::ECellTypeRow)
+			{
+			ParamLimitVarieties& nextLimits = paramLimits[paramLimitsIndex];
+			numValues = std::accumulate(nextLimits.begin(), nextLimits.end(), 0);
+			}
+		else
+			{
+			numValues = aNumVarieties;
+			}
+
+		bool mirrorJustification = (aMirrored && cellName == KCellNameJustification);
+		OptimizeNewLineCellData(aIndexMap, aTempBytes, values, nextCellFlag, numValues, aNumVarieties, paramLimits[paramLimitsIndex], cellName, mirrorJustification);
+		}
+	}
+
+void CMLCompDataInstOpt::OptimizeNewLineCellData(
+	IndexMap& aIndexMap, 
+	vector<char>& aTempBytes, 
+	TMLCompDataValues& aValues, 
+	unsigned int& aNextCell, 
+	int aTotalParams,
+	int aNumVarieties, 
+	CMLCompDataInstOpt::ParamLimitVarieties& aParamLimitVarieties, 
+	string cellName,
+	bool aMirrorJustification)
+	{
+	// build up the values for each variety 
+	// if the valid values for each variety are the same, then we can store them once only
+	// in which case there will be as many values as the variety with the largest number of values
+	vector<string> optimizedValues; 
+
+	// also build up the found valid values in case we can't optimize
+	vector<string> foundValues; 
+
+	bool optimizeVarieties = true;
+	bool optimizeCalcs = true;
+	int numCalcs = 0;
+	int* largestParamLimitPtr = max_element(aParamLimitVarieties.begin(), aParamLimitVarieties.end());
+	int largestParamLimit = largestParamLimitPtr != aParamLimitVarieties.end() ? *largestParamLimitPtr : 0;
+	
+	// in the case of there being no calcs at all, we don't want to be optimizing,
+	// in order to avoid wasted flags.
+	if(largestParamLimit == 1)
+		optimizeCalcs = false;
+
+	TMLCompDataValues::TCompDataCellType type = TMLCompDataValues::Type(cellName);
+	bool isColRow = (type == TMLCompDataValues::ECellTypeCol ||	type == TMLCompDataValues::ECellTypeRow);
+
+	// only go up to the max variety, as any data past that may be from a spurious merged instance
+	for(int varietyIndex = 0; varietyIndex < aNumVarieties; varietyIndex++)
+		{
+		TMLCompDataZoomLevels& zoomLevels = aValues[varietyIndex];
+		TMLCompDataCalcs* calcs = &(zoomLevels[iZoomLevel]);
+		if(!calcs->size())
+			calcs = &(zoomLevels[EAknUiZoomNormal]);
+		numCalcs = calcs->size();
+		string value;
+		vector<string> foundCalcs; 
+		int paramLimit = aParamLimitVarieties[varietyIndex];
+		if(numCalcs == 0)
+			{
+			if(varietyIndex == 0)
+				optimizedValues.push_back(value);
+			if(varietyIndex > 0 && !(optimizedValues[0].empty()))
+				optimizeVarieties = false;
+			foundCalcs.push_back(value);
+			}
+		else
+			{
+			for(int index = 0; index < numCalcs; index++)
+				{
+				bool needToCheckIndexValidity = !isColRow || (index < paramLimit);
+				value = (*calcs)[index];
+				value = aMirrorJustification ? TMLCompDataValues::MirrorJustificationValue(value) : value;
+
+				if(index >= optimizedValues.size() && index < largestParamLimit) // index is zero based, size is quantity
+					{
+					// store the first valid value for a given index that we find.
+					// note that this will pick up additional values in subsequent varieties
+					optimizedValues.push_back(value);
+					}
+				else if(needToCheckIndexValidity && value != optimizedValues[index]) 
+					{
+					// so if it doesn't match, we can't optimize
+					optimizeVarieties = false;
+					}
+
+				// collect the valid found values as we go, in case we aren't able to optimize
+				if(needToCheckIndexValidity)
+					{
+					foundCalcs.push_back(value);
+					}
+				}
+			}
+		if(isColRow)
+			{
+			int found = foundCalcs.size();
+			if(!found)
+				{
+				foundCalcs.push_back(string());
+				found++;
+				}
+			if(found > 1)
+				{
+				optimizeCalcs = false;
+				}
+			}
+		else
+			{
+			optimizeCalcs = false;
+			}
+		copy(foundCalcs.begin(), foundCalcs.end(), back_inserter(foundValues));
+		}
+
+	if(optimizeVarieties && isColRow)
+		{
+		// now that we know the optimized values, fill missing values by repeating the last one.
+		// but if we're optimizing the calcs, then we don't want to expand them after all
+		if(!optimizeCalcs)
+			{
+			int optimal = optimizedValues.size();
+			string value = optimal > 0 ? optimizedValues[optimal-1] : string();
+			for(; optimal < largestParamLimit; optimal++)
+				{
+				optimizedValues.push_back(value);
+				}
+			}
+		}
+
+	if(optimizeVarieties && aNumVarieties == 1)
+		{
+		optimizeVarieties = false;
+		}
+
+	vector<string>& valuesToEncode = optimizeVarieties ? optimizedValues : foundValues;
+	EncodeNewLineCellData(aIndexMap, aTempBytes, valuesToEncode, aNextCell, aTotalParams, optimizeVarieties, optimizeCalcs);
+	}
+
+void CMLCompDataInstOpt::EncodeNewLineCellData(
+	IndexMap& aIndexMap, 
+	vector<char>& aTempBytes, 
+	vector<string>& aValuesToEncode, 
+	unsigned int& aNextCell,
+	int aTotalMax,
+	bool aOptimizeVarieties,
+	bool aOptimizeCalcs)
+	{
+	// encode the actual data into the temporary bytestream
+	int numOptimizedVals = aValuesToEncode.size();
+	if(numOptimizedVals > 0)
+		{
+		for(vector<string>::iterator pString = aValuesToEncode.begin(); pString != aValuesToEncode.end(); ++pString)
+			{
+			EncodeValue(aTempBytes, *pString);
+			}
+		}
+	else
+		{
+		EncodeValue(aTempBytes, "");
+		}
+
+	if(numOptimizedVals > aTotalMax)
+		throw GeneralErr("bad index in indexMap");
+	
+	// if there is only one value stored, we can make a further optimization
+	// as we know that all values must be the same, however they are stored
+	// so in that case, don't store an index map entry
+	if(numOptimizedVals > 1)
+		{
+		// update the index map, 
+		// put the flags at the right hand side, to avoid it becoming multi-byte in general
+		int optimizeVarietiesMask = (aOptimizeVarieties ? 1 : 0);
+		int optimizeCalcsMask = (aOptimizeCalcs ? 1 : 0) << 1;
+		int numValsMask = (numOptimizedVals) << 2;
+		int indexField = (numValsMask | optimizeCalcsMask | optimizeVarietiesMask);
+		aIndexMap[indexField] |= aNextCell;
+		}
+	aNextCell = aNextCell << 1;
+	}
+
+void CMLCompDataInstOpt::CountApiParams(CCdlTkImplementation& aApi, int& aParams)
+	{
+	aParams = 0;
+	const CCdlTkApiParams& params = aApi.Api().AsFunc().Params();
+	for (CCdlTkApiParams::const_iterator pParam = params.begin(); pParam != params.end(); ++pParam)
+		{
+		if (pParam->Type() == KTypeInt) // is it a cell index parameter
+			aParams++;
+		}
+	}
+
+void CMLCompDataInstOpt::ValidateRequiredParams(string aApiName, CCdlTkApiParams& aParams, bool aOption, bool aColumn, bool aRow)
+	{
+	// check that data matches api
+	bool matches = true;
+	matches &= ((aOption) == (aParams.FindByName(KParamOptionIndex) != aParams.end()));
+	matches &= ((aColumn) == (aParams.FindByName(KParamColIndex) != aParams.end()));
+	matches &= ((aRow) == (aParams.FindByName(KParamRowIndex) != aParams.end()));
+	if(!matches)
+		throw CdlTkAssert(string("layout data does not match CDL API : ") + aApiName);
+	}
+
+void CMLCompDataInstOpt::SetGenericFunc(CMLCompDataInstOptImpl& aImpl, SCompDataImplFunc::TFuncType aType)
+	{
+	CCdlTkFunctionApi& api = const_cast<CCdlTkFunctionApi&>(aImpl.iImpl->Api().AsFunc());
+	CCdlTkApiParams& params = api.Params();
+
+	SCompDataImplFunc& func = AddImplFunc(aType, params);
+	aImpl.iImpl->SetPointerReference(func.iPtrRef);
+	}
+
+void CMLCompDataInstOpt::SetLineFunc(CMLCompDataLineInstOptImpl& aImpl)
+	{
+	SCompDataImplFunc::TFuncType type = SCompDataImplFunc::EWindowLine;
+	if (aImpl.iLine->iType == TMLCompDataLine::ETextComponent)
+		{
+		type = SCompDataImplFunc::ETextLine;
+		}
+	string name = aImpl.iImpl->Name();
+
+	// look up the api to see whether we need the params
+	CCdlTkFunctionApi& api = const_cast<CCdlTkFunctionApi&>(aImpl.iImpl->Api().AsFunc());
+	CCdlTkApiParams& params = api.Params();
+	ValidateRequiredParams(
+		name, 
+		params, 
+		iAllParams || aImpl.iLine->NeedsOptions(), 
+		iAllParams || aImpl.iLine->NeedsCols(), 
+		iAllParams || aImpl.iLine->NeedsRows());
+	SCompDataImplFunc& func = AddImplFunc(type, params);
+	aImpl.iImpl->SetPointerReference(func.iPtrRef);
+	}
+
+void CMLCompDataInstOpt::SetSubTableFunc(CMLCompDataSubTableInstOptImpl& aImpl)
+	{
+	TMLCompDataTable& table = *(aImpl.iTable);
+	TMLCompDataTable::TMLCompDataSubTable& subTable = *(aImpl.iSubTable);
+	TMLCompDataLine& line= *(table[subTable[0]]);
+
+	SCompDataImplFunc::TFuncType type = SCompDataImplFunc::EWindowTable;
+
+	if (line.iType == TMLCompDataLine::ETextComponent)
+		{
+		type = SCompDataImplFunc::ETextTable;
+		}
+	string name = aImpl.iImpl->Name();
+
+	CCdlTkFunctionApi& api = const_cast<CCdlTkFunctionApi&>(aImpl.iImpl->Api().AsFunc());
+	CCdlTkApiParams& params = api.Params();
+
+	string debug;
+	for(CCdlTkApiParams::iterator pParam = params.begin(); pParam != params.end(); ++pParam)
+		debug = pParam->Name();
+
+	ValidateRequiredParams(
+		name, 
+		params, 
+		iAllParams || subTable.iNeedsOption, 
+		iAllParams || subTable.iNeedsCol, 
+		iAllParams || subTable.iNeedsRow);
+	SCompDataImplFunc& func = AddImplFunc(type, params);
+	aImpl.iImpl->SetPointerReference(func.iPtrRef);
+	}
+
+bool CMLCompDataInstOpt::HasApi(const string& aName)
+	{
+	return iInterface.ApiList().Find(aName) != 0;
+	}
+
+CCdlTkImplementation& CMLCompDataInstOpt::FindImp(const string& aName)
+	{
+	CCdlTkImplementation* impl = iInstance->Impl().Find(aName);
+	if (!impl)
+		throw NotFoundErr(aName + " in interface " + iInterface.FileName());
+	return *impl;
+	}
+
+CMLCompDataInstOptImpl* CMLCompDataInstOpt::FindSimilarImpl(const CMLCompDataInstOptImpls& aImpls, const CCdlTkImplementation& aImpl)
+	{
+	for (CMLCompDataInstOptImpls::const_iterator pOptImpl = aImpls.begin(); pOptImpl != aImpls.end(); ++pOptImpl)
+		{
+		CMLCompDataInstOptImpl* optImpl = *pOptImpl;
+		if (optImpl->iImpl == &aImpl)
+			return optImpl;
+		}
+	return NULL;
+	}
+
+string CMLCompDataInstOpt::DefinitionString(int aByteCodeIndex, const string& aApiName)
+	{
+	int adjustedIndex = aByteCodeIndex - iBaseOffset;
+	return CdlTkUtil::ShortToHexString(adjustedIndex) + ",\t// (" + CdlTkUtil::IntToHexString(aByteCodeIndex) + ") " + aApiName;
+	}
+
+bool CMLCompDataInstOpt::CheckByteCodeIndexInRange(int aByteCodeIndex)
+	{
+	int adjustedIndex = aByteCodeIndex - iBaseOffset;
+	if(adjustedIndex > KAddressableBytecodedData)
+		{
+		cerr << "Error: Out of range: index = "  << CdlTkUtil::IntToHexString(aByteCodeIndex) << ", ";
+		cerr << "baseOffset = " << CdlTkUtil::IntToHexString(iBaseOffset ) << endl;
+		return false;
+		}
+	return true;
+	}
+
+SCompDataImplFunc& CMLCompDataInstOpt::AddImplFunc(SCompDataImplFunc::TFuncType aType)
+	{
+	CCdlTkApiParams params;
+	return AddImplFunc(aType, params);
+	}
+
+SCompDataImplFunc& CMLCompDataInstOpt::AddImplFunc(SCompDataImplFunc::TFuncType aType, CCdlTkApiParams& aParams)
+	{
+	for (CImplFuncs::iterator pFunc = iFuncs.begin(); pFunc != iFuncs.end(); ++pFunc)
+		{
+		SCompDataImplFunc& func = **pFunc;
+		if(func.IsSimilar(aType, aParams))
+			return func;
+		}
+
+	int count = gTheFuncs.size();
+	for (int ii=0; ii<count; ii++)
+		{
+		SCompDataImplFunc* func = &gTheFuncs[ii];
+		if(func->IsSimilar(aType, aParams)) 
+			{
+			iFuncs.push_back(func);
+			return *func;
+			}
+		}
+
+	throw NotFoundErr("implementation function");
+	return gTheFuncs[0];
+	}
+
+void CMLCompDataInstOpt::SetGenericAPI(SCompDataImplFunc::TFuncType aType, const string& aName)
+	{
+	CCdlTkImplementation* impl = iInstance->Impl().Find(aName);
+
+	// CMLCompDataInstOptImpl(CCdlTkImplementation* aImpl);
+	CMLCompDataInstOptImpl* newImpl = new CMLCompDataInstOptImpl(impl);
+	iImpls.push_back(newImpl);
+
+	SetGenericFunc(*newImpl, aType);
+	newImpl->iImpl->SetDefinition(CdlTkUtil::ShortToHexString(0) + ","); // no specific data for generic apis
+	}
+
+// The following strings and the SetExtraCpp() function build the gross structure of
+// the C++ customisation instance.
+// So far, the implementations are actually just 16-bit values, typically indexes into
+// the data lookup table. These need to be turned into an array by adding declarations
+// and brackets to the first and last implementations. Extra support functions are also
+// added.
+// extern string KScalableExtraCpp;
+string KScalableExtraCpp = "\
+#include \"aknlayout2scalabledecode.h\"\n\
+namespace $INTERFACE_NS { extern const TUint8 KByteCodedData_$FIRSTINSTANCENAME[]; }\n";
+
+//extern string KScalableInitialCpp;
+string KScalableInitialCpp ="\
+extern const TUint16 KDataLookup[$INTERFACE_NS::E_TApiId_TableSize];\n\
+const SCompDataImplData KImplData = { KDataLookup, $INTERFACE_NS::KByteCodedData_$FIRSTINSTANCENAME + $THISINSTANCEBASEOFFSET };\n\
+\n\
+$FUNCTIONS\
+\n\
+const TUint16 KDataLookup[$INTERFACE_NS::E_TApiId_TableSize] =\n\
+\t{\n";
+void CMLCompDataInstOpt::SetExtraCpp(const string& aFirstInstName)
+	{
+	// The "extra cpp" field is written to the top of the cpp file.
+	CdlTkUtil::CReplaceSet cppSet;
+	cppSet.Add("$INTERFACE_NS", iInterface.NamespaceName());
+	cppSet.Add("$FIRSTINSTANCENAME", aFirstInstName);
+	cppSet.Add("$THISINSTANCEBASEOFFSET", CdlTkUtil::IntToHexString(iBaseOffset)); // base offset can be longer than 16 bits
+	iInstance->SetExtraCpp(CdlTkUtil::MultiReplace(cppSet, KScalableExtraCpp));
+
+	// add headers & fwd declarations
+	string init = CdlTkUtil::MultiReplace(cppSet, KScalableInitialCpp);
+
+	// add decode functions
+	string functions;
+	for (CImplFuncs::iterator pFunc = iFuncs.begin(); pFunc != iFuncs.end(); ++pFunc)
+		{
+		CdlTkUtil::AppendString(functions, (*pFunc)->iDefn);
+		CdlTkUtil::AppendString(functions, "\n");
+		}
+	init = CdlTkUtil::Replace("$FUNCTIONS", functions, init);
+	CCdlTkImplementation& first = **(iInstance->Impl().begin());
+	first.SetDefinition(init + first.Definition());
+
+	// add end of data table
+	CCdlTkImplementation& last = **(iInstance->Impl().end() - 1);
+	last.SetDefinition(last.Definition() + "\n};");
+	}
+
+void CMLCompDataInstOpt::OutputStats()
+	{
+	int optimizedBytes(0);
+	int unoptimizedBytes(0);
+	for (CMLCompDataInstOptImpls::iterator pImpl = iImpls.begin(); pImpl != iImpls.end(); ++pImpl)
+		{
+		int size = (*pImpl)->iBytes.size();
+		if ((*pImpl)->iIsRedirectedToExactCopy)
+			optimizedBytes += size;
+		else
+			unoptimizedBytes += size;
+		}
+	for (CMLCompDataInstOptImpls::iterator pTableImpl = iTableImpls.begin(); pTableImpl != iTableImpls.end(); ++pTableImpl)
+		{
+		int size = (*pTableImpl)->iBytes.size();
+		if ((*pTableImpl)->iIsRedirectedToExactCopy)
+			optimizedBytes += size;
+		else
+			unoptimizedBytes += size;
+		}
+
+	float compress = (100.0 * (float)unoptimizedBytes) / ((float)optimizedBytes + (float)unoptimizedBytes);
+	int compressInt = (int)(compress + 0.5);
+	cout << "instance " << iName << " compressed to " << compressInt << "% of total (" << unoptimizedBytes<< " / " << optimizedBytes + unoptimizedBytes << ")" << endl;
+	}
+
+void CMLCompDataInstOpt::AddTableToInstance(TMLCompDataTable& aTable, TMLCompDataTable::TMLCompDataSubTable& aSub, int /*aTableNum*/)
+	{
+	string tableName = MLCompDataToCdl::SubTableApiName(aSub);
+	string tableParamLimitsName = tableName + KFuncParamLimitsSuffix;
+
+	if (HasApi(tableName))
+		{
+		CCdlTkImplementation& impl = FindImp(tableName);
+		CMLCompDataSubTableInstOptImpl* newImpl = new CMLCompDataSubTableInstOptImpl(&aTable, &aSub, &impl);
+		iTableImpls.push_back(newImpl);
+
+		SetDummyTableData(aTable, aSub, *newImpl);
+		SetSubTableFunc(*newImpl);
+
+		AddTableLimitsImpl(tableName + KFuncLimitsSuffix, aSub);
+		if (HasApi(tableParamLimitsName))
+			{
+			AddTableParamLimitsImpl(tableParamLimitsName, newImpl->iByteCodeIndex, SCompDataImplFunc::ETableParamLimits, aSub.iNeedsOption);
+			}
+		AddTableImpl(tableName, aTable, aSub);
+		}
+	}
+
+void CMLCompDataInstOpt::UpdateTableInstance(TMLCompDataTable& aTable, TMLCompDataTable::TMLCompDataSubTable& aSub, CMLCompDataInstOptImpl* aImpl)
+	{
+	string tableName = MLCompDataToCdl::SubTableApiName(aSub);
+	UpdateTableData(aTable, aSub, *aImpl);
+
+	// if we can find the new table data in the aggregated data, point to that instead
+	int foundIndex = iInstances.FindSimilarBytes(aImpl, iBaseOffset);
+	if(foundIndex >= 0)
+		{
+		if(foundIndex != aImpl->iByteCodeIndex)
+			{
+			aImpl->iByteCodeIndex = foundIndex;
+			aImpl->iIsRedirectedToExactCopy = true;
+			}
+		else
+			{
+			cerr << "Error: found same table already in bytestream: " << aImpl->iName << endl;
+			}
+		}
+
+	// now we've generated the bytecode, it will be added to the bytestream
+	iInstances.AddImpl(aImpl);
+	aImpl->iImpl->SetDefinition(DefinitionString(aImpl->iByteCodeIndex, tableName));
+
+	string tableParamLimitsName = tableName + KFuncParamLimitsSuffix;
+	if (HasApi(tableParamLimitsName))
+		{
+		UpdateTableParamLimitsImpl(tableParamLimitsName, aImpl->iByteCodeIndex);
+		}
+	}
+
+void CMLCompDataInstOpt::AddTableParamLimitsImpl(const string& aApiName, int aByteCodeIndex, SCompDataImplFunc::TFuncType aType, bool aNeedsOptions)
+	{
+	CCdlTkImplementation& impl = FindImp(aApiName);
+
+	// look up the api to see whether we need a variety params
+	CCdlTkFunctionApi& api = const_cast<CCdlTkFunctionApi&>(impl.Api().AsFunc());
+	CCdlTkApiParams& params = api.Params();
+	ValidateRequiredParams(
+		aApiName, 
+		params, 
+		iAllParams || aNeedsOptions, 
+		false, 
+		false);
+
+	SCompDataImplFunc& func = AddImplFunc(aType, params);
+
+	impl.SetDefinition(DefinitionString(aByteCodeIndex, aApiName));
+	impl.SetPointerReference(func.iPtrRef);
+	}
+
+void CMLCompDataInstOpt::UpdateTableParamLimitsImpl(const string& aApiName, int aByteCodeIndex)
+	{
+	CCdlTkImplementation& paramLimitsImpl = FindImp(aApiName);
+	paramLimitsImpl.SetDefinition(DefinitionString(aByteCodeIndex, aApiName));
+	}
+
+void CMLCompDataInstOpt::AddTableLimitsImpl(const string& aApiName, TMLCompDataTable::TMLCompDataSubTable& aSubTable)
+	{
+	CCdlTkImplementation& impl = FindImp(aApiName);
+	AddTableLimitsImplDefn(aSubTable, impl);
+	impl.SetPointerReference(AddImplFunc(SCompDataImplFunc::ETableLimits).iPtrRef);
+	}
+
+void CMLCompDataInstOpt::AddTableLimitsImplDefn(TMLCompDataTable::TMLCompDataSubTable& aSubTable, CCdlTkImplementation& aImpl)
+	{
+	// code up table limits as a pair of byte values, the first byte is the first table
+	// index, the second is the last table index.
+	int first = (*aSubTable.begin()) & 0xff;
+	int last = (*aSubTable.rbegin()) & 0xff;
+
+	// however, we want these APIs to be accessed zero based, so have to calculate the offset.
+	int offset = last - first;
+
+    int v = offset;
+	if ( v > KAddressableBytecodedData )
+	    {
+	    std::cerr << "*** ERROR: Value " << v << "(unknown/3) of out range" << std::endl;
+	    }
+	    
+	aImpl.SetDefinition(CdlTkUtil::ShortToHexString(offset) + KComma);
+	}
+
+void CMLCompDataInstOpt::AddTableImpl(const string& aApiName, TMLCompDataTable& aTable, TMLCompDataTable::TMLCompDataSubTable& aSub)
+	{
+	CCdlTkImplementation& impl = FindImp(aApiName);
+
+	int nParams;
+	CountApiParams(impl, nParams);
+	nParams--;	// don't count the aLineIndex param
+	SCompDataImplFunc::TFuncType type = SCompDataImplFunc::EWindowTable;
+	TMLCompDataLine::TComponentType subTableType = aTable[aSub[0]]->iType;
+	switch(subTableType)
+		{
+		case TMLCompDataLine::ETextComponent:
+			{
+			type = SCompDataImplFunc::ETextTable;
+			break;
+			}
+		}
+	CCdlTkFunctionApi& api = const_cast<CCdlTkFunctionApi&>(impl.Api().AsFunc());
+	CCdlTkApiParams& params = api.Params();
+	ValidateRequiredParams(
+		aApiName, 
+		params, 
+		iAllParams || aSub.iNeedsOption, 
+		iAllParams || aSub.iNeedsCol, 
+		iAllParams || aSub.iNeedsRow);
+	SCompDataImplFunc& func = AddImplFunc(type, params);
+	}
+
+void CMLCompDataInstOpt::AddParamLimits(TMLCompDataLine& aLine, bool aNeedsOptions)
+	{
+	string apiName = MLCompDataToCdl::LineApiName(aLine) ;
+	string paramLimitsApiName = apiName + KFuncParamLimitsSuffix;
+	if (!HasApi(paramLimitsApiName))
+		throw NotFoundErr(paramLimitsApiName + " in interface " + iInterface.FileName());
+
+	CCdlTkImplementation& paramLimitsImpl = FindImp(paramLimitsApiName);
+
+	// look up the api to see whether we need a variety params
+	CCdlTkFunctionApi& api = const_cast<CCdlTkFunctionApi&>(paramLimitsImpl.Api().AsFunc());
+	CCdlTkApiParams& params = api.Params();
+	ValidateRequiredParams(
+		paramLimitsApiName, 
+		params, 
+		iAllParams || aNeedsOptions, 
+		false, 
+		false);
+
+	SCompDataImplFunc& func = AddImplFunc(SCompDataImplFunc::ELineParamLimits, params);
+	paramLimitsImpl.SetPointerReference(func.iPtrRef);
+
+	UpdateParamLimits(apiName);
+	}
+
+void CMLCompDataInstOpt::UpdateParamLimits(const string& apiName)
+	{
+	string paramLimitsApiName = apiName + KFuncParamLimitsSuffix;
+	if (HasApi(paramLimitsApiName))
+		{
+		CCdlTkImplementation& paramLimitsImpl = FindImp(paramLimitsApiName);
+		CMLCompDataInstOptImpl* actualOptImpl = FindSimilarImpl(iImpls, FindImp(apiName));
+		
+		paramLimitsImpl.SetDefinition(DefinitionString(actualOptImpl->iByteCodeIndex, paramLimitsApiName));
+		}
+	}
+
+void CMLCompDataInstOpt::SetDummyTableData(TMLCompDataTable& aTable, TMLCompDataTable::TMLCompDataSubTable& aSubTable, CMLCompDataInstOptImpl& aImpl)
+	{
+	aImpl.iBytes.clear();
+	aImpl.iComment = string("for table: ");
+	aImpl.iName = MLCompDataToCdl::SubTableApiName(aSubTable);
+	EncodeValue(aImpl.iBytes, aSubTable.size());
+	for(TMLCompDataTable::TMLCompDataSubTable::iterator pLineId = aSubTable.begin(); pLineId != aSubTable.end(); ++pLineId)
+		{
+		aImpl.iBytes.push_back(0);
+		aImpl.iBytes.push_back(0);
+		}
+	}
+
+void CMLCompDataInstOpt::UpdateTableData(TMLCompDataTable& aTable, TMLCompDataTable::TMLCompDataSubTable& aSubTable, CMLCompDataInstOptImpl& aImpl)
+	{
+	aImpl.iBytes.clear();
+	EncodeValue(aImpl.iBytes, aSubTable.size());
+	for(TMLCompDataTable::TMLCompDataSubTable::iterator pLineId = aSubTable.begin(); pLineId != aSubTable.end(); ++pLineId)
+		{
+		// figure out the offset to the next line of the table
+		TMLCompDataLine& line = *(aTable[*pLineId]);
+		string lineName = MLCompDataToCdl::LineApiName(line) ;
+		CMLCompDataInstOptImpl* lineImpl = FindSimilarImpl(iImpls, FindImp(lineName));
+
+		// we must store the adjusted index, ie relative to the base offset, in the definition, as that will be used 
+		// in the main output, so check that the offset is in range, which it should be if we've updated the lines
+		// correctly
+		if(!CheckByteCodeIndexInRange(lineImpl->iByteCodeIndex))
+			throw GeneralErr(aImpl.iName + " in interface " + iInterface.FileName());
+		int adjustedIndex = lineImpl->iByteCodeIndex - iBaseOffset;
+
+		// make an assumption that data fits into 16 bits, and don't encode the lookups
+		// that way, when decoding, we can jump forward by 2 bytes * index without decoding
+		// all the values (since they're not encoded, we know they're all the same size)
+		aImpl.iBytes.push_back((adjustedIndex & 0xff00) >> 8);
+		aImpl.iBytes.push_back(adjustedIndex);
+		}
+	}
+
+struct SIdToInt
+	{
+	int iInt;
+	char* iStr;
+	};
+
+#include <avkon.hrh>
+extern SIdToInt gIdToIntTable[];
+extern const int gIdToIntTableCount;
+extern void TranslateValue(string& aValue);
+
+void CMLCompDataInstOpt::EncodeValue(vector<char>& aBytes, string aValue)
+	{
+	int pos = 0;
+	TranslateValue(aValue);
+	if (aValue == "")
+		{
+		aBytes.push_back(KByteEmpty);
+		}
+	else 
+		{
+		pos = aValue.find_first_of(KParentRelativeMarker);
+		if(pos != string::npos)
+			{
+			if (pos != 0)
+				throw CdlTkAssert(string("arithmetic parser not good enough : ") + aValue);
+			int val = CdlTkUtil::ParseInt(aValue.substr(1));
+			EncodeParentRelativeValue(aBytes, val);
+			}
+		else
+			{
+			int val = CdlTkUtil::ParseInt(aValue);
+			EncodeValue(aBytes, val);
+			}
+		}
+	}
+
+void CMLCompDataInstOpt::EncodeValue(vector<char>& aBytes, int aValue)
+	{
+	if (0 <= aValue && aValue <= KMaxSingleByteValue)
+		{
+		aBytes.push_back(aValue);
+		}
+	else if (aValue > KMaxSingleByteValue && aValue <= KMaxDoubleByteValue)
+		{
+		aBytes.push_back(KByteWord);
+		aBytes.push_back((aValue & 0xff00) >> 8);
+		aBytes.push_back(aValue);
+		}
+	else
+		{
+		aBytes.push_back(KByteLong);
+		aBytes.push_back((aValue & 0xff000000) >> 24);
+		aBytes.push_back((aValue & 0x00ff0000) >> 16);
+		aBytes.push_back((aValue & 0x0000ff00) >> 8);
+		aBytes.push_back(aValue);
+		}
+	}
+
+void CMLCompDataInstOpt::EncodeParentRelativeValue(vector<char>& aBytes, int aValue)
+	{
+	if (KMinSingleByteParentRelativeValue <= aValue && aValue <= KMaxSingleByteParentRelativeValue)
+		{
+		aBytes.push_back(KByteP1);
+		aBytes.push_back(aValue);
+		}
+	else
+		{
+		aBytes.push_back(KByteP2);
+		aBytes.push_back((aValue & 0xff00) >> 8);
+		aBytes.push_back(aValue);
+		}
+	}
+
+void CMLCompDataInstOpt::MirrorParamName(string& aParamName)
+	{
+	if (aParamName == KParamNameL)
+		aParamName = KParamNameR;
+	else if (aParamName == KParamNameR)
+		aParamName = KParamNameL;
+	}
+
+//
+// MLCompDataCdlInstanceOpt
+//
+
+MLCompDataCdlInstanceOpt::InstStruct::InstStruct(string aInstName, TMLCompData* aInst, TMLAttributes* aAttribs) 
+	: 
+	iInstName(aInstName), 
+	iInst(aInst),
+	iAttribs(aAttribs)
+	{
+	}
+
+MLCompDataCdlInstanceOpt::InstList::~InstList() 
+	{
+	for(InstList::iterator pNext = begin(); pNext != end(); ++pNext)
+		{
+		delete pNext->iInst;
+		}
+	}
+
+void MLCompDataCdlInstanceOpt::ProcessSeparators(vector<string>& args, vector<int>& aSeparators)
+	{
+    for(int arg = 3; arg < args.size(); arg++)
+        {
+        if(args[arg] == "-a")
+            aSeparators.push_back(arg);
+        }
+
+    aSeparators.push_back(args.size()); // add an implicit last separator
+    if(aSeparators.size() < 2)
+        throw MLCompDataCdlInstanceOptArgsErr();
+
+    // check that the distance between each separator is not a multiple of 2 
+    // i.e. counting the steps between aSeparators ( sep -> xml -> inst -> sep) is 3 steps
+    // i.e. counting the steps between aSeparators ( sep -> xml -> inst -> xml -> inst -> sep) is 5 steps
+    for(int sep = 0; sep < aSeparators.size() - 1; sep++)
+        {
+        int delta = aSeparators[sep+1] - aSeparators[sep]; 
+	    if (delta%2 == 0)
+		    throw MLCompDataCdlInstanceOptArgsErr();
+        }
+	}
+
+bool MLCompDataCdlInstanceOpt::CheckForUsedInstances(
+	const CInstanceList& aUsedList, 
+	const CZoomLevelNames& aZoomLevelNames,
+	const vector<string>& aArgs, 
+	const vector<int>& aSeparators, 
+	int aSepIndex)
+	{
+	bool ok = false;
+	for(CZoomLevelNames::const_iterator pZoomLevel = aZoomLevelNames.begin(); pZoomLevel != aZoomLevelNames.end(); ++pZoomLevel)
+		{
+		// check if any of these instances are used - skip this if none are used
+		for (int arg = aSeparators[aSepIndex] + 1; arg < aSeparators[aSepIndex+1]; arg += 2)
+			{
+			string instName = aArgs[arg+1] + "_" + pZoomLevel->second;
+			if (aUsedList.IsInstanceOk(instName))
+				ok = true;
+			}
+		}
+	return ok;
+	}
+
+void MLCompDataCdlInstanceOpt::ParseInstances(const vector<string>& aArgs, const vector<int>& aSeparators, int aSepIndex, MLCompDataCdlInstanceOpt::InstList& aInstList)
+	{
+	for (int arg = aSeparators[aSepIndex] + 1; arg < aSeparators[aSepIndex+1]; arg += 2)
+		{
+		string layoutName = aArgs[arg];
+		string instName = aArgs[arg+1];
+		string attribsName = CdlTkUtil::Replace(KCompDataFileNameSuffix, KAttributesFileNameSuffix, layoutName);
+
+		auto_ptr<TMLCompDataParseLayout> layoutParse = TMLCompDataParseLayout::Parse(layoutName);
+		auto_ptr<TMLCompData> layout(layoutParse.get());
+		layoutParse.release();
+
+		auto_ptr<TMLAttributesParse> attribsParse = TMLAttributesParse::Parse(attribsName);
+		auto_ptr<TMLAttributes> attribs(attribsParse.get());
+		attribsParse.release();
+
+		InstStruct instStruct(instName, layout.get(), attribs.get());
+		aInstList.push_back(instStruct);
+		layout.release();
+		attribs.release();
+		}
+	}
+
+void MLCompDataCdlInstanceOpt::MergeLayouts(CInstanceList& aInstUsedList, CZoomLevelNames& aZoomLevelNames, const InstList& aInstances, InstList& aMergedLayouts)
+	{
+	// start with the non-mirrored instances
+	for(int count = 0; count < 2; count++)
+		{
+		bool isMirrored = (count != 0);
+		// first iterate through the layouts, we will generate one instance per layout
+		for(int instIndex = 0; instIndex < aInstances.size(); instIndex++)
+			{
+			const InstStruct& instStruct = aInstances[instIndex];
+			string targetInstName = instStruct.iInstName;
+			TMLCompData& targetLayout = *(instStruct.iInst);
+			TMLAttributes& targetAttribs = *(instStruct.iAttribs);
+
+			bool required = false;
+			for(CZoomLevelNames::const_iterator pZoomLevel = aZoomLevelNames.begin(); pZoomLevel != aZoomLevelNames.end(); ++pZoomLevel)
+				{
+				string zoomInstName = targetInstName + "_" + pZoomLevel->second;
+				 if(aInstUsedList.IsInstanceOk(zoomInstName))
+					required = true;
+				}
+
+			// if this target is not required, or if it's the wrong sort of mirrored
+			// for this iteration, skip it.
+			if(targetLayout.iCanBeMirror != isMirrored || !required)
+				continue;
+
+			// for each instance, we must merge all the other layouts
+			auto_ptr<TMLCompData> mergedLayout(new TMLCompData());
+			auto_ptr<TMLAttributes> mergedAttribs(new TMLAttributes());
+			for (InstList::const_iterator pInst2 = aInstances.begin(); pInst2 != aInstances.end(); ++pInst2)
+				{
+				// merge in all the others
+				const InstStruct& instStruct2 = *pInst2;
+				if(instStruct2.iInstName != targetInstName)
+					{
+					TMLCompData& nextLayout = *(instStruct2.iInst);
+					TMLAttributes& nextAttribs = *(instStruct2.iAttribs);
+					// but only if it's the right kind of mirrored
+					if(nextLayout.iCanBeMirror == isMirrored)
+						{
+						mergedLayout->Merge(nextLayout);
+						mergedAttribs->Merge(nextAttribs);
+						}
+					}
+				}
+			// then end up merging in the one we want
+			mergedLayout->Merge(targetLayout);
+			mergedAttribs->Merge(targetAttribs);
+			if(isMirrored)
+				{
+				// If we have just processed a mirrored layout, 
+				// we need to do a mirror merge with the corresponding one.
+				// The instances are ordered as on the command line, 
+				// but the merged layouts are grouped toghether, unmirrored first.
+				// So to convert between the two indexes: 1 -> 0, and 3 -> 1
+				int unMirroredMergedLayoutIndex = (instIndex / 2);
+				InstStruct& unMirroredInst = aMergedLayouts[unMirroredMergedLayoutIndex]; // this works as we have already added the unmirrored instance to the vector
+				TMLCompData& unMirroredLayout = *(unMirroredInst.iInst);
+				TMLAttributes& unMirroredAttribs = *(unMirroredInst.iAttribs);
+				mergedLayout->Merge(unMirroredLayout);
+				mergedAttribs->Merge(unMirroredAttribs);
+				}
+
+			InstStruct mergedInstStruct(targetInstName, mergedLayout.get(), mergedAttribs.get());
+			aMergedLayouts.push_back(mergedInstStruct);
+			mergedLayout.release();
+			mergedAttribs.release();
+			}
+		}
+	}
+
+int MLCompDataCdlInstanceOpt::Process(vector<string>& args)
+	{
+	// parse the file containing the used instances list. only instances in this list 
+	// will be generated, even if also mentioned on the command line
+	CInstanceList instUsedList;
+	instUsedList.ProcessOptions(args);
+
+	// extract the zoom level names, note that this consumes the argument if present
+	CZoomLevelNames zoomLevelNames;
+	zoomLevelNames.ProcessOptions(args);
+
+	// check that we have an acceptable number of arguments
+	int extraArgs = args.size() - 3;
+	if (extraArgs < 0)
+		throw MLCompDataCdlInstanceOptArgsErr();
+
+	// check for optional flags
+    int arg = 2;
+	bool allParams = false;
+	if (args[arg] == "-allparams")
+		{
+		allParams = true;
+		arg++;
+		}
+
+	bool nonCompleteInstance = false;
+	if(args[arg].substr(0,2) == "-d")
+        {
+		arg++;
+        if (args[arg].size() >= 2)
+		    {
+		    nonCompleteInstance = true;
+		    }
+        }
+
+	// parse the CDL interface
+	string cdlName = args[arg];
+	CCdlTkCdlFileParser parser(cdlName);
+	auto_ptr<CCdlTkInterface> iface(parser.LoadAndParse(true));
+	MLCompDataCdlInstanceOpt process(*iface);
+
+    // the separators divide the layout instances that are aggregated together
+    vector<int> separators;
+	ProcessSeparators(args, separators);
+    for(int sep = 0; sep < separators.size() - 1; sep++)
+        {
+		if(!CheckForUsedInstances(instUsedList, zoomLevelNames, args, separators, sep))
+			continue;
+        // start from after the next separator, and continue until before the next one
+	    InstList instances;
+		ParseInstances(args, separators, sep, instances);
+
+		InstList mergedLayouts;
+		MergeLayouts(instUsedList, zoomLevelNames, instances, mergedLayouts);
+		for(InstList::iterator pMergedLayout = mergedLayouts.begin(); pMergedLayout != mergedLayouts.end(); )
+			{
+			process.AddInst(*pMergedLayout, zoomLevelNames, allParams, nonCompleteInstance); // pass ownership of mergedLayout
+			pMergedLayout = mergedLayouts.erase(pMergedLayout);
+			}
+        }
+
+	process.Process();
+	process.WriteInstances();
+	return 0;
+	}
+
+void MLCompDataCdlInstanceOpt::ShowHelp(ostream& stream)
+	{
+	stream << "MLCompCdl2InstO [-i<instanceList>] [-z<zoomList>] [-allparams] [-d<deliveryType>] <interface.cdl> (-a ([-m]<layout.xml> <instanceName>)+ )+" << endl;
+	stream << "  Creates optimised CDL instances containing the layout data." << endl;
+	stream << "  Each -a flag is followed by a collection of xml and instance name pairs." << endl;
+	stream << "  Each collection is aggregated separately." << endl;
+	stream << "  The aggregation of the layout instances must conform to the CDL interface, " << endl;
+	stream << "    but note any missing data in an instance may result in data being returned " << endl;
+	stream << "    from a different instance, although duplicate implementations will be reused " << endl;
+	stream << "    to reduce ROM usage." << endl;
+	stream << "  A -m flag must precede an xml file that contains mirrored layout data." << endl;
+	stream << "  An aggregated collection of layouts must contain interleaved" << endl;
+	stream << "    elaf and the corresponding abrw instances." << endl;
+	stream << "  If -i<instanceList> is specified, then only instances whose name" << endl;
+	stream << "    appears in the file <instanceList> will be processed." << endl;
+	stream << "  If -z<zoomList> is specified, then only instances whose zoom factor" << endl;
+	stream << "   (in the form \"n,string\") appears in the file <zoomList> will be generated." << endl;
+	stream << "  If -allparams is used, all processed APIs will have all available params added, " << endl;
+	stream << "    otherwise only needed params are added." << endl;
+	stream << "  If -d<deliveryType> is supplied with any value, any API that has a missing" << endl;
+	stream << "    implementation will be filled in with NULL, allowing fall-through to an instance" << endl;
+	stream << "    from a lower priority pack." << endl;
+	}
+
+MLCompDataCdlInstanceOpt::MLCompDataCdlInstanceOpt(CCdlTkInterface& aInterface)
+	: 
+	iInterface(aInterface)
+	{
+	}
+
+MLCompDataCdlInstanceOpt::~MLCompDataCdlInstanceOpt()
+	{
+	for(CCompDataZoomLevelDatas::iterator pZoomLevel = iZoomLevelDatas.begin(); pZoomLevel != iZoomLevelDatas.end(); ++pZoomLevel)
+		{
+		CCompDatas& compDatas = pZoomLevel->second;
+		for (CCompDatas::iterator pInstOpt = compDatas.begin(); pInstOpt != compDatas.end(); ++pInstOpt)
+			delete *pInstOpt;
+		}
+	for(CCompDataLayouts::iterator pLayout = iLayouts.begin(); pLayout != iLayouts.end(); ++pLayout)
+		 delete *pLayout;
+	}
+
+void MLCompDataCdlInstanceOpt::AddInst(const InstStruct& aInstStruct, CZoomLevelNames& aZoomLevelNames, bool aAllParams, bool aNonCompleteInstance)
+	{
+	TMLCompData* layout = aInstStruct.iInst;
+	layout->iAttributes = aInstStruct.iAttribs; // transfer ownership
+	iLayouts.push_back(aInstStruct.iInst);
+	for(CZoomLevelNames::iterator pZoomLevel = aZoomLevelNames.begin(); pZoomLevel != aZoomLevelNames.end(); ++pZoomLevel)
+		{
+		auto_ptr<CMLCompDataInstOpt> p(new CMLCompDataInstOpt(*this, layout, aInstStruct.iInstName, pZoomLevel->second, pZoomLevel->first, aAllParams, aNonCompleteInstance));
+		CCompDatas& compDatas = iZoomLevelDatas[pZoomLevel->first];
+		compDatas.push_back(p.get());
+		p.release();
+		}
+	}
+
+void MLCompDataCdlInstanceOpt::Process()
+	{
+	for(CCompDataZoomLevelDatas::iterator pZoomLevel = iZoomLevelDatas.begin(); pZoomLevel != iZoomLevelDatas.end(); ++pZoomLevel)
+		{
+		CCompDatas& compDatas = pZoomLevel->second;
+		if(compDatas.size() == 0)
+			continue;
+		CMLCompDataInstOpt* firstInstOpt = compDatas[0];
+		cout << "processing instances for zoom level: " << firstInstOpt->ZoomName() << endl;
+
+		string firstInstName = firstInstOpt->Name();
+		for (CCompDatas::iterator pLayout = compDatas.begin(); pLayout != compDatas.end(); ++pLayout)
+			(*pLayout)->Process(firstInstName);
+		}
+	ProcessCommonImpl();
+	}
+
+void MLCompDataCdlInstanceOpt::WriteInstances()
+	{
+	bool found = false;
+	for(CCompDataZoomLevelDatas::iterator pZoomLevel = iZoomLevelDatas.begin(); pZoomLevel != iZoomLevelDatas.end(); ++pZoomLevel)
+		{
+		CCompDatas& compDatas = pZoomLevel->second;
+		if(!found && compDatas.size() > 0)
+			{
+			found = true;
+			cout << "writing instances ... " << endl;
+			}
+		for (CCompDatas::iterator pLayout = compDatas.begin(); pLayout != compDatas.end(); ++pLayout)
+			(*pLayout)->WriteInstance();
+		}
+	}
+
+CCdlTkInterface& MLCompDataCdlInstanceOpt::Interface()
+	{
+	return iInterface;
+	}
+
+const string KCommonImplStart = "\
+#include \"aknlayout2scalabledecode.h\"\n\
+namespace $NAMESPACENAME { extern TUint8 const KByteCodedData_$FIRSTINSTANCENAME[] = {\n";
+
+const string KCommonImplImpl = "\
+// $INDEX $COMMENT\n\
+$BYTES\n";
+
+void MLCompDataCdlInstanceOpt::ProcessCommonImpl()
+	{
+	// use the first instance name of the first zoom level
+	// it's not entirely accurate but it only needs to disambiguate
+	CCompDatas& compDatas = iZoomLevelDatas[EAknUiZoomNormal];
+	if(compDatas.size() == 0)
+		return;
+	CMLCompDataInstOpt* firstInstOpt = compDatas[0];
+
+	CdlTkUtil::CReplaceSet startImplSet;
+	startImplSet.Add("$NAMESPACENAME", iInterface.NamespaceName());
+	startImplSet.Add("$FIRSTINSTANCENAME", firstInstOpt->Name());
+	string bytecode = CdlTkUtil::MultiReplace(startImplSet, KCommonImplStart);
+	int byteCounter(0);
+
+	for (CMLCompDataInstOptImpls::iterator pImpl = iImpls.begin(); pImpl != iImpls.end(); ++pImpl)
+		{
+		vector<char>& bytes = (*pImpl)->iBytes;
+		if (!(*pImpl)->iIsRedirectedToExactCopy && bytes.size())
+			{
+			string byteString;
+			for (vector<char>::iterator pChar = bytes.begin(); pChar != bytes.end(); ++pChar)
+				{
+				CdlTkUtil::AppendString(byteString, CdlTkUtil::CharToHexString(*pChar));
+				CdlTkUtil::AppendString(byteString, KComma);
+				}
+
+			// in this case, we want to know the absolute index to help with debugging
+			int index = (*pImpl)->iByteCodeIndex;
+			if(byteCounter != index)
+				{
+				cerr << "Error: Data table mismatch for " << (*pImpl)->iName;
+				cerr << ": Bytecode index = " << CdlTkUtil::ShortToHexString(index);
+				cerr << "; byte counter = " << CdlTkUtil::ShortToHexString(byteCounter) << endl;
+				throw GeneralErr((*pImpl)->iName + " in interface " + iInterface.FileName());
+				}
+			byteCounter += bytes.size();
+
+			CdlTkUtil::CReplaceSet implSet;
+			implSet.Add("$INDEX", CdlTkUtil::IntToHexString(index));
+			implSet.Add("$COMMENT", (*pImpl)->iComment + (*pImpl)->iName + " (" + CdlTkUtil::ShortToHexString(bytes.size()) + " bytes)");
+			implSet.Add("$BYTES", byteString);
+			CdlTkUtil::AppendString(bytecode, CdlTkUtil::MultiReplace(implSet, KCommonImplImpl));
+			}
+		}
+	CdlTkUtil::AppendString(bytecode, "};\n}");
+	CCdlTkInstance& firstInst = firstInstOpt->Inst();
+	firstInst.SetExtraCpp(bytecode);
+	}
+
+int MLCompDataCdlInstanceOpt::FindSimilarBytes(CMLCompDataInstOptImpl* aImpl, int aBaseOffset)
+	{
+	int index = -1;
+	vector<char>::iterator startOfAddressableBlock = iBytesAggregated.begin() + aBaseOffset;
+	vector<char>::iterator found = std::search(
+		startOfAddressableBlock, 
+		iBytesAggregated.end(), 
+		aImpl->iBytes.begin(), 
+		aImpl->iBytes.end());
+	if(found != iBytesAggregated.end())
+		{
+		index = std::distance(iBytesAggregated.begin(), found); // we return the absolute position
+		}
+	return index;
+	}
+
+void MLCompDataCdlInstanceOpt::AddImpl(CMLCompDataInstOptImpl* aImpl)
+	{
+	if(!aImpl->iIsRedirectedToExactCopy)
+		{
+		CMLCompDataInstOptImpls::iterator found = std::find(iImpls.begin(), iImpls.end(), aImpl);
+		if(found == iImpls.end())
+			{
+			iImpls.push_back(aImpl);
+			}
+		else
+			{
+			cerr << "Error: " << aImpl->iName << " already added to byte stream" << endl;
+			throw GeneralErr(aImpl->iName + " in interface " + iInterface.FileName());
+			}
+		if (aImpl->iBytes.size())
+			{
+			aImpl->iByteCodeIndex = iBytesAggregated.size();
+			iBytesAggregated.insert(
+				iBytesAggregated.end(), 
+				aImpl->iBytes.begin(), 
+				aImpl->iBytes.end());
+			}
+		}
+	}
+
+int MLCompDataCdlInstanceOpt::ByteStreamSize() const
+	{
+	return iBytesAggregated.size();
+	}
+
+// end of file
+
+