/*
* 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),
iParams(aParams),
iDefn(aDefn),
iPtrRef(aPtrRef)
{
}
SCompDataImplFunc(TFuncType aType, string aDefn, string aPtrRef)
:
iType(aType),
iDefn(aDefn),
iPtrRef(aPtrRef)
{
}
bool IsSimilar(TFuncType aType, CCdlTkApiParams& aParams)
{
if(iType != aType)
return false;
unsigned int size = iParams.size();
if(size != aParams.size())
return false;
for(unsigned 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 gTheCompDataFuncs;
//
// 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::const_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)
:
CMLCompDataInstOptImpl(aImpl),
iTable(aTable),
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),
iInterface(iInstances.Interface()),
iZoomLevel(aZoomLevel),
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 (CMLCompDataInstOptImpls::iterator 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 (TMLCompData::iterator 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 (TMLCompData::iterator 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 (unsigned int 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;
unsigned int numCalcs = 0;
int* largestParamLimitPtr = max_element(aParamLimitVarieties.begin(), aParamLimitVarieties.end());
unsigned 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;
unsigned 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(unsigned 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)
{
unsigned 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 = gTheCompDataFuncs.size();
for (int ii=0; ii<count; ii++)
{
SCompDataImplFunc* func = &gTheCompDataFuncs[ii];
if(func->IsSimilar(aType, aParams))
{
iFuncs.push_back(func);
return *func;
}
}
throw NotFoundErr("implementation function");
return gTheCompDataFuncs[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;
// }
// }
if ( TMLCompDataLine::ETextComponent == subTableType )
{
type = SCompDataImplFunc::ETextTable;
}
CCdlTkFunctionApi& api = const_cast<CCdlTkFunctionApi&>(impl.Api().AsFunc());
CCdlTkApiParams& params = api.Params();
ValidateRequiredParams(
aApiName,
params,
iAllParams || aSub.iNeedsOption,
iAllParams || aSub.iNeedsCol,
iAllParams || aSub.iNeedsRow);
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)
{
string::size_type 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(unsigned 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(unsigned 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(unsigned int instIndex = 0; instIndex < aInstances.size(); instIndex++)
{
const InstStruct& instStruct = aInstances[instIndex];
string targetInstName = CdlTkUtil::Replace("\r","",instStruct.iInstName);
targetInstName = CdlTkUtil::Replace("\n","",targetInstName);
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(unsigned 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