/*
* Copyright (c) 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:
*
*/
#include <f32file.h>
#include <utf.h>
#include <xml/documentparameters.h>
#include "creator_scriptparser.h"
#include "creator_scriptelementfactory.h"
#include "creator_traces.h"
using namespace Xml;
CCreatorScriptParser::CCreatorScriptParser()
: iDefaultElement(TCreatorScriptElementInfo(TCreatorScriptElementInfo::EStatusUndefined, 0))
{
}
void CCreatorScriptParser::ConstructL(CCreatorEngine* aEngine)
{
LOGSTRING("Creator: CCreatorScriptParser::ConstructL");
iEngine = aEngine;
}
CCreatorScriptParser* CCreatorScriptParser::NewL(CCreatorEngine* aEngine)
{
LOGSTRING("Creator: CCreatorScriptParser::NewL");
CCreatorScriptParser* self = CCreatorScriptParser::NewLC(aEngine);
CleanupStack::Pop();
return self;
}
CCreatorScriptParser* CCreatorScriptParser::NewLC(CCreatorEngine* aEngine)
{
LOGSTRING("Creator: CCreatorScriptParser::NewLC");
CCreatorScriptParser* self = new (ELeave) CCreatorScriptParser;
CleanupStack::PushL(self);
self->ConstructL(aEngine);
return self;
}
CCreatorScriptParser::~CCreatorScriptParser()
{
delete iParser;
if( iElementStack.Count() > 0 )
{
delete iElementStack[0].iElement;
}
iElementStack.Reset();
iElementStack.Close();
}
void CCreatorScriptParser::GetTextFileMode(RFile& aFile, TInt& aFileSize)
{
LOGSTRING("Creator: CCreatorScriptParser::GetTextFileMode");
iScriptTextFormat = EFormatANSIASCII;
// if we are working with text files, check the type first
TBuf8<4> BOM;
// first check for UTF-16
if (aFileSize >= 2 && aFile.Read(0, BOM, 2) == KErrNone)
{
if (BOM.Length()==2 && BOM[0]==0xFF && BOM[1]==0xFE)
{
iScriptTextFormat = EFormatUTF16LE;
aFileSize -= 2;
return;
}
else if (BOM.Length()==2 && BOM[0]==0xFE && BOM[1]==0xFF)
{
iScriptTextFormat = EFormatUTF16BE;
aFileSize -= 2;
return;
}
}
// then check for UTF-8
if (aFileSize >= 3 && aFile.Read(0, BOM, 3) == KErrNone)
{
if (BOM.Length()==3 && BOM[0]==0xEF && BOM[1]==0xBB && BOM[2]==0xBF)
{
iScriptTextFormat = EFormatUTF8;
aFileSize -= 3;
return;
}
}
// none of those, seek back to beginning
TInt pos(0);
aFile.Seek(ESeekStart, pos);
}
void CCreatorScriptParser::ParseL(const TDesC& aFileName)
{
LOGSTRING2("Creator: CCreatorScriptParser::ParseL: %S", &aFileName);
// Create and start XML-parser
if( iParser == 0)
{
_LIT8(KXmlMimeType, "text/xml");
iParser = CParser::NewL(KXmlMimeType, *this);
}
RFs filesession;
CleanupClosePushL(filesession);
User::LeaveIfError( filesession.Connect() );
Xml::ParseL(*iParser, filesession, aFileName);
CleanupStack::PopAndDestroy(&filesession); // filesession
}
void CCreatorScriptParser::ParseL(RFile& aFile)
{
LOGSTRING("Creator: CCreatorScriptParser::ParseL");
TInt filesize = 0;
aFile.Size(filesize);
GetTextFileMode(aFile, filesize);
// Create and start XML-parser
if( iParser == 0)
{
_LIT8(KXmlMimeType, "text/xml");
iParser = CParser::NewL(KXmlMimeType, *this);
}
Xml::ParseL(*iParser, aFile);
}
void CCreatorScriptParser::OnStartDocumentL(const Xml::RDocumentParameters& aDocParam, TInt aErrorCode)
{
LOGSTRING2("Creator: CCreatorScriptParser::OnStartDocumentL (Error code: %d)", aErrorCode);
User::LeaveIfError(aErrorCode);
const TDesC8& charSet = aDocParam.CharacterSetName().DesC();
}
void CCreatorScriptParser::OnEndDocumentL(TInt aErrorCode)
{
LOGSTRING2("Creator: CCreatorScriptParser::OnEndDocumentL (Error code: %d)", aErrorCode);
User::LeaveIfError(aErrorCode);
}
void CCreatorScriptParser::OnStartPrefixMappingL( const RString& /*aPrefix*/,
const RString& /*aUri*/,
TInt aErrorCode)
{
LOGSTRING2("Creator: CCreatorScriptParser::OnStartPrefixMappingL (Error code: %d)", aErrorCode);
User::LeaveIfError(aErrorCode);
}
void CCreatorScriptParser::OnEndPrefixMappingL(const RString& /*aPrefix*/, TInt aErrorCode)
{
LOGSTRING2("Creator: CCreatorScriptParser::OnEndPrefixMappingL (Error code: %d)", aErrorCode);
User::LeaveIfError(aErrorCode);
}
void CCreatorScriptParser::OnIgnorableWhiteSpaceL(const TDesC8& /*aBytes*/, TInt aErrorCode)
{
LOGSTRING2("Creator: CCreatorScriptParser::OnIgnorableWhiteSpaceL (Error code: %d)", aErrorCode);
User::LeaveIfError(aErrorCode);
}
void CCreatorScriptParser::OnSkippedEntityL(const RString& /*aName*/, TInt aErrorCode)
{
LOGSTRING2("Creator: CCreatorScriptParser::OnSkippedEntityL (Error code: %d)", aErrorCode);
User::LeaveIfError(aErrorCode);
}
void CCreatorScriptParser::OnProcessingInstructionL( const TDesC8& /*aTarget*/,
const TDesC8& /*aData*/,
TInt aErrorCode)
{
LOGSTRING2("Creator: CCreatorScriptParser::OnProcessingInstructionL (Error code: %d)", aErrorCode);
User::LeaveIfError(aErrorCode);
}
void CCreatorScriptParser::OnError(TInt aErrorCode)
{
LOGSTRING2("Creator: CCreatorScriptParser::OnError: %d", aErrorCode);
iLastError = aErrorCode;
// Delete all elements from the stack:
while(iElementStack.Count() > 0 )
{
TCreatorScriptElementInfo previousElem = LastElementInfo();
delete previousElem.iElement;
previousElem.iElement = 0;
iElementStack.Remove(iElementStack.Count()-1);
}
}
TAny* CCreatorScriptParser::GetExtendedInterface(const TInt32 aUid)
{
LOGSTRING2("Creator: CCreatorScriptParser::GetExtendedInterface (UID: %d)", aUid);
return this;
}
const TCreatorScriptElementInfo& CCreatorScriptParser::LastElementInfo() const
{
LOGSTRING("Creator: CCreatorScriptParser::LastElementInfo");
if(iElementStack.Count() > 0)
{
return iElementStack[iElementStack.Count()-1];
}
return iDefaultElement;
}
/**
* Create an element and add attributes to it.
*/
void CCreatorScriptParser::OnStartElementL( const RTagInfo& aElement,
const RAttributeArray& aAttributes,
TInt aErrorCode)
{
LOGSTRING2("Creator: CCreatorScriptParser::OnStartElementL (Error code: %d)", aErrorCode);
User::LeaveIfError(aErrorCode);
const TDesC8& elementName8 = aElement.LocalName().DesC();
HBufC* elementName16 = Convert8BitTo16BitLC(elementName8);
const TCreatorScriptElementInfo& context = LastElementInfo();
CCreatorScriptElement* element = 0;
if( context.iElement )
{
HBufC* fullContext = HBufC::NewL(
context.iElement->Context().Length() +
context.iElement->Name().Length() +
2);
CleanupStack::PushL(fullContext);
if(context.iElement->Context() != KNullDesC &&
context.iElement->Context().Length() > 0 )
{
fullContext->Des().Copy(context.iElement->Context());
_LIT(KContextSeparator, "::");
fullContext->Des().Append(TPtrC(KContextSeparator));
}
const TDesC& parentName = context.iElement->Name();
if(parentName.Length() > 0 )
{
fullContext->Des().Append(parentName);
}
element = TCreatorScriptElementFactory::CreateElementL( iEngine,
elementName16->Des(),
fullContext->Des());
CleanupStack::PopAndDestroy(fullContext); // fullContext
}
else
{
element = TCreatorScriptElementFactory::CreateElementL(iEngine, elementName16->Des());
}
CleanupStack::PopAndDestroy(elementName16);
CleanupStack::PushL(element);
if( element == 0 )
{
// Add NULL pointer to stack. Otherwise the stack would go out of sync. in ::OnEndElement().
TCreatorScriptElementInfo info(TCreatorScriptElementInfo::EStatusParsing, element);
iElementStack.AppendL(info);
CleanupStack::Pop(element);
return;
}
// Add attributes to the element:
TInt attrCount = aAttributes.Count();
for(TInt i = 0; i < attrCount; ++i)
{
const RAttribute& attribute = aAttributes[i];
const RTagInfo& nameInfo = attribute.Attribute();
const TDesC8& attrName8 = nameInfo.LocalName().DesC();
const TDesC8& value8 = attribute.Value().DesC();
// Convert data to 16 bit:
HBufC* attrName16 = Convert8BitTo16BitLC(attrName8);
HBufC* value16 = Convert8BitTo16BitLC(value8);
CCreatorScriptAttribute* scriptAttr = CCreatorScriptAttribute::NewLC(attrName16->Des(), value16->Des());
element->AddAttributeL(scriptAttr);
CleanupStack::Pop(scriptAttr);
CleanupStack::PopAndDestroy(value16);
CleanupStack::PopAndDestroy(attrName16);
}
// Save element to the stack:
TCreatorScriptElementInfo info(TCreatorScriptElementInfo::EStatusParsing, element);
iElementStack.AppendL(info);
CleanupStack::Pop(element);
}
/**
* Executes the command if needed. Also caches the element for future use, if needed.
*/
void CCreatorScriptParser::OnEndElementL(const RTagInfo& /*aElement*/, TInt aErrorCode)
{
LOGSTRING2("Creator: CCreatorScriptParser::OnEndElementL (Error code: %d)", aErrorCode);
User::LeaveIfError(aErrorCode);
if( iElementStack.Count() == 0 )
{
return;
}
// Get element from the stack:
TCreatorScriptElementInfo elementInfo = LastElementInfo();
if( elementInfo.iElement == 0 )
{
// Remove element from the stack:
iElementStack.Remove(iElementStack.Count()-1);
return;
}
// Execute the command if this is a command element:
if( elementInfo.iElement->IsCommandElement() )
{
elementInfo.iElement->ExecuteCommandL();
}
// Remove element from the stack:
iElementStack.Remove(iElementStack.Count()-1);
// Get the previous element from the stack:
if( iElementStack.Count() > 0 )
{
TCreatorScriptElementInfo previousElem = LastElementInfo();
if( previousElem.iElement->IsRoot() )
{
// This element is not a sub-element (except of the root element, of course).
if( elementInfo.iElement->IsCacheNeeded() )
{
// Add element to the cache, since it will be needed in future.
elementInfo.iElement->AddToCacheL();
}
//else
// {
// Not needed anymore, so element can be deleted:
delete elementInfo.iElement;
elementInfo.iElement = 0;
// }
}
else
{
// There is a parent element (other than root), so we add this element
// as a sub-element fot it.
previousElem.iElement->AddSubElementL(elementInfo.iElement);
}
}
else
{
// Delete root element, which will delete recursively all sub-elements:
delete elementInfo.iElement;
elementInfo.iElement = 0;
}
}
/**
* Add content to element.
*/
void CCreatorScriptParser::OnContentL(const TDesC8& aBytes, TInt aErrorCode)
{
LOGSTRING2("Creator: CCreatorScriptParser::OnContentL (Error code: %d)", aErrorCode);
User::LeaveIfError(aErrorCode);
if( iElementStack.Count() > 0 )
{
HBufC* contentData = Convert8BitTo16BitLC(aBytes);
TCreatorScriptElementInfo elementInfo = iElementStack[iElementStack.Count()-1];
if( elementInfo.iElement )
{
elementInfo.iElement->AppendContentL(*contentData);
}
CleanupStack::PopAndDestroy(contentData);
}
}
HBufC16* CCreatorScriptParser::Convert8BitTo16BitLC(const TDesC8& aInput)
{
LOGSTRING("Creator: CCreatorScriptParser::Convert8BitTo16BitLC");
HBufC16* output = NULL;
output = CnvUtfConverter::ConvertToUnicodeFromUtf8L(aInput);
CleanupStack::PushL(output);
return output;
}
TInt CCreatorScriptParser::GetError() const
{
return iLastError;
}