Many of the components were not compilingm,because bld.inf had undefined flag #ifdef RD_CUSTOMIZABLE_AI. All the flags removed now. Components do not compile right away. E.g. many icons are missing and need to be copied from Symbian3. See example from MCSPlugin. Shortcut plugin does not need to be compiled as MCSPlugin replaces it.
/*
* Copyright (c) 2002-2005 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: Implementation of XCFW Engine
*
*/
// INCLUDE FILES
#include "xcfwengine.h"
#include "gecoobjectfactorybase.h"
#include "gecodefaultobject.h"
#include "xcfwtree.h"
#include "xcfwlocalizer.h"
#include "xcfwpanic.h"
#include "xcfwentityconverter.h"
#include <gmxmlnode.h>
#include <gmxmlelement.h>
#include <gmxmlcomposer.h>
#include <gmxmldocument.h>
#include <gmxmlcharacterdata.h>
#include <gmxmltext.h>
#include <gmxmlcdatasection.h>
// CONSTANTS
// default XML declaration
_LIT( KXMLDeclaration, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
// default Doctype declaration
_LIT( KDocTypeDecl, "<!DOCTYPE xcfwml SYSTEM \"%S\">");
_LIT( KDocTypeDeclNoDTD, "<!DOCTYPE xcfwml>");
_LIT( KMmsDTD, "mms_smil.dtd"); //this is autogenerated by GMXML if no DTD decl.
_LIT( KXCFWAnd, "&" );
_LIT( KXCFWSemiC, ";" );
_LIT( KDTDExt, ".dtd" );
_LIT( KLocFormat, "%0*d\\");
const TInt KDTDExtLen = 4; // ".dtd"
const TInt KLocFormatLen = 7; // "%0*d\\"
//Entity reference extra character count
const TInt KExtraChars = 2;
const TInt KMaxDTDLength = 160;
// ============================ MEMBER FUNCTIONS ===============================
// -----------------------------------------------------------------------------
// CXCFWEngine::CXCFWEngine
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CXCFWEngine::CXCFWEngine(
MXCFWEngineObserver* aObserver ):
CActive( CActive::EPriorityStandard )
{
iObserver = aObserver;
CActiveScheduler::Add( this );
}
// -----------------------------------------------------------------------------
// CXCFWEngine::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CXCFWEngine::ConstructL()
{
//Create default object factory
iDefaultFactory = CGECODefaultObjectFactory::NewL();
iState = EStateIdle;
}
// -----------------------------------------------------------------------------
// CXCFWEngine::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
EXPORT_C CXCFWEngine* CXCFWEngine::NewL(
MXCFWEngineObserver* aObserver )
{
__ASSERT_LEAVE( aObserver!=NULL, KErrArgument );
CXCFWEngine* self = new( ELeave ) CXCFWEngine( aObserver ) ;
CleanupStack::PushL( self );
self->ConstructL();
CleanupStack::Pop( self );
return self;
}
// Destructor
EXPORT_C CXCFWEngine::~CXCFWEngine()
{
if ( IsActive() )
{
Cancel();
}
// Reset object factory array (factories are not owned)
iFactoryList.Reset();
iFactoryList.Close();
// delete default object factory
delete iDefaultFactory;
// delete xml parser
delete iParser;
// delete XML composer
delete iComposer;
// delete XML document object
delete iXMLDoc;
// delete XML file name buffer
delete iFile;
// delete DTD file name buffer
delete iDTD;
// delete localizer instance
delete iLocalizer;
// delete node text buffer
delete iNodeText;
// Set non-owned pointers to NULL
iCurrentXMLNode = NULL;
if ( iTree )
{
iTree->SetLocked( EFalse );
iTree = NULL;
}
iCurrentTreeNode = NULL;
iObserver = NULL;
//Close file system handle (just in case)
iFileSystem.Close();
}
// -----------------------------------------------------------------------------
// CXCFWEngine::RunL
// Engine conducts itself according to internal state.
// -----------------------------------------------------------------------------
//
void CXCFWEngine::RunL()
{
TRequestStatus *s = &iStatus;
switch ( iState )
{
case EStateInitializingLoad:
{
//Instantiate parser and request parsing. If ParseFile returns
//an error code, it is most probably a file that is not found
//or it can't be currently accessed => leave.
//we'll get notification from parser through ParseFileCompleteL
//when ready.
iState = EStateLoadingFile;
delete iParser;
iParser = NULL;
iParser = CMDXMLParser::NewL( this );
User::LeaveIfError (
iParser->ParseFile( iFileSystem, iFile->Des() ) );
break;
}
case EStateInitializingSave:
{
if ( iLocalizer && iLocalizer->LastError() != KErrNone )
{
iObserver->HandleEngineErrorL ( KErrGeneral );
Cancel();
FreeResources();
}
else
{
iState = EStateConstructingDOM;
SetActive();
User::RequestComplete( s, KErrNone );
}
break;
}
case EStateParsing: //Constructing XCFWTree from DOM
{
if ( iCurrentXMLNode )
{
iTree->SetLocked( EFalse );
DOM2TreeNextCycleL();
iTree->SetLocked( ETrue );
iState = EStateParsing;
SetActive();
User::RequestComplete( s, KErrNone );
}
else
{
iState = EStateIdle;
//free parsing resources
iObserver->HandleEngineEventL(
MXCFWEngineObserver::EEvtParsingComplete );
FreeResources();
}
#ifdef __XCFW_MODULE_TEST
iObserver->HandleEngineEventL( MXCFWEngineObserver::EEvtNull );
#endif
break;
}
case EStateConstructingDOM: //Constructing DOM from XCFW Tree
{
if ( iCurrentTreeNode )
{
iTree->SetLocked( EFalse );
Tree2DOMNextCycleL();
iTree->SetLocked( ETrue );
iState = EStateConstructingDOM;
SetActive();
User::RequestComplete( s, KErrNone );
}
else
{
iTree->SetLocked( EFalse );
iState = EStateSavingFile;
//delete possible previous instance of composer
//and create new.
delete iComposer;
iConverter = NULL; //Deleted by composer
iConverter = new ( ELeave ) CXCFWEntityConverter;
iComposer = CMDXMLComposer::NewL( this );
iComposer->SetEntityConverter( iConverter );
// Ask composer to compose the file.
// we'll get notification about the op through
// ComposeFileCompleteL
User::LeaveIfError(
iComposer->ComposeFile(
iFileSystem, iFile->Des(), iXMLDoc, EUtf8 ) );
}
#ifdef __XCFW_MODULE_TEST
iObserver->HandleEngineEventL( MXCFWEngineObserver::EEvtNull );
#endif
break;
}
case EStateIdle: //idle state, not doing anything
{
break;
}
default:
{
break;
}
}
}
// -----------------------------------------------------------------------------
// CXCFWEngine::RunError
// Notify observer about the error and free resources
// -----------------------------------------------------------------------------
//
TInt CXCFWEngine::RunError(
TInt aError )
{
TInt ret = KErrNone;
iStateByLastError = iState;
FreeResources();
TRAP( ret, iObserver->HandleEngineErrorL( aError ) );
return ret;
}
// -----------------------------------------------------------------------------
// CXCFWEngine::DoCancel
// Notify observer about operation cancellation and free resources.
// -----------------------------------------------------------------------------
//
void CXCFWEngine::DoCancel()
{
TInt state = iState;
FreeResources();
switch ( state )
{
case EStateInitializingLoad: //fallthrough
case EStateParsing:
{
TInt err = 0;
TRAP(err, iObserver->HandleEngineEventL(
MXCFWEngineObserver::EEvtParsingCanceled ) );
break;
}
case EStateInitializingSave: //fallthrough
case EStateConstructingDOM:
{
TInt err = 0;
TRAP(err, iObserver->HandleEngineEventL(
MXCFWEngineObserver::EEvtSavingCanceled ) );
break;
}
default:
break;
}
}
// -----------------------------------------------------------------------------
// CXCFWEngine::CancelOperation
// -----------------------------------------------------------------------------
//
EXPORT_C void CXCFWEngine::CancelOperation()
{
Cancel();
//in case engine was not active, need to free the resources here.
FreeResources();
}
// -----------------------------------------------------------------------------
// CXCFWEngine::LoadL
// Wrapper to support loading of XML without giving a DTD file name (i.e. when
// loading content that has no localized strings)
// -----------------------------------------------------------------------------
//
EXPORT_C void CXCFWEngine::LoadL(
MXCFWTree& aTree,
const TDesC& aFile )
{
LoadL( aTree, aFile, KNullDesC );
}
// -----------------------------------------------------------------------------
// CXCFWEngine::LoadL
// XML loading operation is started. Internal members are initialized and
// object is set active.
// -----------------------------------------------------------------------------
//
EXPORT_C void CXCFWEngine::LoadL(
MXCFWTree& aTree,
const TDesC& aFile,
const TDesC& aDTDFile )
{
// If we're active at the moment or iState is something else than Idle,
// leave with KErrInUse.
if ( IsActive() || iState != EStateIdle )
{
User::Leave( KErrInUse );
}
User::LeaveIfError( iFileSystem.Connect() );
//delete previous instances of parser and DTD name buffers
delete iParser;
iParser = NULL;
delete iDTD;
iDTD = NULL;
iDTD = aDTDFile.AllocL();
delete iFile;
iFile = NULL;
iFile = aFile.AllocL();
//Set tree to use (not owned)
iTree = &aTree;
if ( iTree->Root () )
{
//if the tree has already a root, we'll load items under that root
iCurrentTreeNode = iTree->Root();
}
else
{
iCurrentTreeNode = NULL;
}
iStateByLastError = EStateIdle;
//Reset possible DTD name
iTree->SetDTDNameL( aDTDFile );
iTree->SetLocked( ETrue );
delete iParser;
iParser = NULL;
iParser = CMDXMLParser::NewL( this );
User::LeaveIfError (
iParser->ParseFile( iFileSystem, iFile->Des() ) );
iState = EStateLoadingFile;
}
// -----------------------------------------------------------------------------
// CXCFWEngine::SaveL
// Wrapper to support saving of XML without giving a DTD file name (i.e. when
// saving content that has no localized strings)
// -----------------------------------------------------------------------------
//
EXPORT_C void CXCFWEngine::SaveL(
MXCFWTree& aTree,
const TDesC& aFile )
{
SaveL( aTree, aFile, aTree.DTDName() );
}
// -----------------------------------------------------------------------------
// CXCFWEngine::SaveL
// Save operation is initialized and started
// -----------------------------------------------------------------------------
//
EXPORT_C void CXCFWEngine::SaveL(
MXCFWTree& aTree,
const TDesC& aFile,
const TDesC& aDTDFile )
{
if ( IsActive() || iState != EStateIdle )
{
User::Leave( KErrInUse );
}
User::LeaveIfError( iFileSystem.Connect() );
//create folder if not exist
TChar bs = '\\';
if ( aFile.Locate( bs ) != KErrNotFound )
{
TPtrC dir = aFile.Left( aFile.LocateReverse( bs ) + 1 );
TInt ret = iFileSystem.MkDirAll( dir );
if ( KErrAlreadyExists != ret && KErrNone != ret )
{
User::Leave( ret );
}
}
//Set tree pointer ( not owned )
iTree = &aTree;
if ( iTree->Root () )
{
//init current tree node to root if there's one
iCurrentTreeNode = iTree->Root();
}
else
{
// this tree can't be saved, has no data
User::Leave( KErrArgument );
}
//delete previous instances of parser and filename buffers
delete iComposer;
iComposer = NULL;
delete iFile;
iFile = NULL;
iFile = aFile.AllocL();
delete iDTD;
iDTD = NULL;
iDTD = aDTDFile.AllocL();
iStateByLastError = EStateIdle;
// delete possible previous instance of XML Doc object
// create new doc and initialize with XML decl + Doctype
delete iXMLDoc;
iXMLDoc = NULL;
iXMLDoc = CMDXMLDocument::NewL();
iXMLDoc->SetVersionTagL( KXMLDeclaration );
// set doc type tag according to given DTD file name
if ( aDTDFile.Compare ( KNullDesC) != 0 )
{
TBuf<KMaxDTDLength> buf;
TInt bsloc = aDTDFile.LocateReverse( bs );
// take just the file name, no preceding path chars
// (the assumption is that loc files are stored
// at relative path \locNN\dtdname.dtd related to
// XML file location)
if ( bsloc != KErrNotFound)
{
TPtrC dtdname = aDTDFile.Mid( bsloc + 1 );
buf.Format( KDocTypeDecl, &dtdname);
}
else
{
buf.Format( KDocTypeDecl, &aDTDFile );
}
iXMLDoc->SetDocTypeTagL( buf );
}
else
{
iXMLDoc->SetDocTypeTagL( KDocTypeDeclNoDTD );
}
// notify observer that we're about to start saving
iObserver->HandleEngineEventL(
MXCFWEngineObserver::EEvtSavingStarted );
iState = EStateInitializingSave;
PrepareEntityConverterAndSetActiveL();
// lock tree to prevent changes during save
iTree->SetLocked( ETrue );
}
// -----------------------------------------------------------------------------
// CXCFWEngine::HasTextData
// returns ETrue if the current xml node has text data under it.
// -----------------------------------------------------------------------------
//
EXPORT_C TBool CXCFWEngine::HasTextData()
{
TBool ret = EFalse;
if ( iCurrentXMLNode && iCurrentXMLNode->FirstChild() )
{
CMDXMLNode::TDOMNodeType t = iCurrentXMLNode->FirstChild()->NodeType();
if ( t == CMDXMLNode::ETextNode || t == CMDXMLNode::ECDATASectionNode )
{
ret = ETrue;
}
}
return ret;
}
// -----------------------------------------------------------------------------
// CXCFWEngine::TextDetailsL
// returns text details for the current XML node (if it has text)
// Node may contain CDATA sections, but mixed content is not supported.
// -----------------------------------------------------------------------------
//
EXPORT_C void CXCFWEngine::TextDetailsL(
TPtrC& aText,
TBool& aIsLocalized )
{
_LIT(KEntityRef, "*&*;*");
TInt err = KErrNotFound;
CMDXMLNode* ptr = iCurrentXMLNode->FirstChild();
if ( ptr )
{
//delete previous text pointer now
delete iNodeText;
iNodeText = NULL;
//loop through all text / cdata elements
while ( ptr &&
( ptr->NodeType() == CMDXMLNode::ETextNode ||
ptr->NodeType() == CMDXMLNode::ECDATASectionNode ) )
{
err = KErrNone;
TPtrC nextdata;
switch ( ptr->NodeType() )
{
case CMDXMLNode::ETextNode:
{
nextdata.Set( ((CMDXMLCharacterData*)ptr)->Data() );
break;
}
case CMDXMLNode::ECDATASectionNode:
{
nextdata.Set( ((CMDXMLCDATASection*)ptr)->Data() );
break;
}
default:
{
err = KErrNotFound;
break;
}
}
if ( KErrNone == err )
{
//create nodetext buffer if we don't have it yet.
if ( !iNodeText )
{
iNodeText = HBufC::NewL( nextdata.Length() );
iNodeText->Des().Copy( nextdata );
}
else
{
//increase nodetext buffer and append new data.
iNodeText = iNodeText->ReAllocL(
iNodeText->Length() + nextdata.Length() );
iNodeText->Des().Append( nextdata );
}
}
ptr = ptr->NextSibling();
}
//If we have some text, do localization
if( iNodeText )
{
err = KErrNone;
aText.Set( *iNodeText );
aIsLocalized = EFalse;
if ( aText.Match( KEntityRef ) != KErrNotFound && iLocalizer)
{
TPtrC ltext;
if ( KErrNone == iLocalizer->EntityRefToText( aText, ltext ) )
{
aText.Set( ltext );
aIsLocalized = ETrue;
}
}
}
}
User::LeaveIfError( err );
}
// -----------------------------------------------------------------------------
// CXCFWEngine::NumAttributes
// return number of attributes for current XML node
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CXCFWEngine::NumAttributes()
{
TInt count = 0;
//Return attribute count for normal element only.
if ( iCurrentXMLNode )
{
if ( iCurrentXMLNode->NodeType() == CMDXMLNode::EElementNode )
{
count = ((CMDXMLElement*)iCurrentXMLNode)->NumAttributes();
}
}
return count;
}
// -----------------------------------------------------------------------------
// CXCFWEngine::AttributeDetailsL
// Function reads attributes from current xml node and returns them in TPtrC's
// -----------------------------------------------------------------------------
//
EXPORT_C void CXCFWEngine::AttributeDetailsL(
const TInt aIndex,
TPtrC& aAttributeName,
TPtrC& aAttributeValue,
TBool& aIsLocalized )
{
_LIT(KEntityRef, "*&*;*");
//Return attribute details for normal element only.
if ( iCurrentXMLNode )
{
if ( iCurrentXMLNode->NodeType() == CMDXMLNode::EElementNode )
{
aIsLocalized = EFalse;
// Get attribute name + value
User::LeaveIfError (
((CMDXMLElement*)iCurrentXMLNode)->
AttributeDetails(aIndex, aAttributeName, aAttributeValue) );
// query localizer component for localized text
if ( aAttributeValue.Match( KEntityRef ) != KErrNotFound
&& iLocalizer )
{
TPtrC ltext;
if ( KErrNone == iLocalizer->EntityRefToText(
aAttributeValue, ltext) )
{
aAttributeValue.Set( ltext );
aIsLocalized = ETrue;
}
}
}
}
}
// -----------------------------------------------------------------------------
// CXCFWEngine::AttributeDetailsL
// Function reads attributes from current xml node and returns them in TPtrC's
// -----------------------------------------------------------------------------
//
EXPORT_C void CXCFWEngine::AttributeDetailsL(
const TInt aIndex,
TPtrC& aAttributeName,
TPtrC& aAttributeValue)
{
//Return attribute details for normal element only.
if ( iCurrentXMLNode )
{
if ( iCurrentXMLNode->NodeType() == CMDXMLNode::EElementNode )
{
// Get attribute name + value
User::LeaveIfError (
((CMDXMLElement*)iCurrentXMLNode)->
AttributeDetails(aIndex, aAttributeName, aAttributeValue) );
}
}
}
// -----------------------------------------------------------------------------
// CXCFWEngine::UnRegisterObjectFactory
// Removes given object factory pointer from factory array. Does not delete.
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CXCFWEngine::UnRegisterObjectFactory(
CGECOObjectFactoryBase* aFactory )
{
TInt err = KErrNotFound;
TInt maxindex = iFactoryList.Count() - 1;
for ( TInt i = maxindex; i >= 0 ; i-- )
{
if ( iFactoryList[i] == aFactory )
{
iFactoryList.Remove(i);
err = KErrNone;
}
}
return err;
}
// -----------------------------------------------------------------------------
// CXCFWEngine::RegisterObjectFactory
// Adds given object factory pointer to factory array. Ownership NOT taken.
// Adding same factory many times is not possible.
// -----------------------------------------------------------------------------
//
EXPORT_C void CXCFWEngine::RegisterObjectFactoryL(
CGECOObjectFactoryBase* aFactory )
{
__ASSERT_LEAVE ( aFactory != NULL, KErrArgument );
TInt maxindex = iFactoryList.Count() - 1;
for ( TInt i = maxindex; i>= 0 ; i-- )
{
if ( iFactoryList[i] == aFactory )
{
User::Leave( KErrAlreadyExists );
}
}
// add to factory array
User::LeaveIfError( iFactoryList.Append( aFactory ) );
}
// -----------------------------------------------------------------------------
// CXCFWEngine::ParseFileCompleteL()
// Detaches parsed XML document from parser. If DTD file was provided in LoadL
// call, we will next load the DTD for getting entity references ready. If no
// DTD file was given, we go straight to parsing.
// -----------------------------------------------------------------------------
//
void CXCFWEngine::ParseFileCompleteL()
{
//see if we have urecoverable errors from GMXML => if error severity is
//fatal, let's not go any further in processing.
if ( iParser->ErrorSeverity() == EXMLFatal )
{
iStateByLastError = iState;
iState = EStateIdle;
iObserver->HandleEngineErrorL( iParser->Error() );
FreeResources();
}
else
{
//delete previous instance of document
if ( iXMLDoc )
{
delete iXMLDoc;
iXMLDoc = NULL;
}
iXMLDoc = iParser->DetachXMLDoc();
iCurrentXMLNode = iXMLDoc->DocumentElement()->FirstChild();
//set up DTD if not already done
PrepareDTDPathL();
TRAPD( err, iObserver->HandleEngineEventL(
MXCFWEngineObserver::EEvtParsingStarted ) );
if ( KErrNone != err )
{
iObserver->HandleEngineErrorL( err );
Cancel();
FreeResources();
}
//Set active
iState = EStateParsing;
PrepareEntityConverterAndSetActiveL();
}
}
// -----------------------------------------------------------------------------
// CXCFWEngine::AddCurrentXMLNodeToTreeL
// New content object is generated, initialized and added to tree. Object
// initialization is done with a registered object factory if there's such.
// Otherwise default object factory is used.
// -----------------------------------------------------------------------------
//
void CXCFWEngine::AddCurrentXMLNodeToTreeL()
{
__ASSERT_LEAVE( iTree && iCurrentXMLNode, KErrGeneral );
CGECOObjectBase* obj = NULL;
CGECOObjectFactoryBase* factory = NULL;
TInt count = iFactoryList.Count();
//XCFW will only handle element nodes.
if ( iCurrentXMLNode->NodeType() == CMDXMLNode::EElementNode )
{
if ( count > 0 )
{
//loop through factories starting from the most recently added
//until a factory returns an object for the given tag or we run
//out of factories.
for ( TInt i = count-1 ; i>= 0 && !obj ; i--)
{
//Query factory for object
factory = iFactoryList[i];
obj = factory->
GetContentObjectAndSetContextL(
iCurrentXMLNode->NodeName() );
}
}
// if none of the user factories recognized this tag,
// use default factory.
if ( !obj )
{
factory = iDefaultFactory;
obj = factory->GetContentObjectAndSetContextL(
iCurrentXMLNode->NodeName() );
}
}
//if we have an object, let's add it to tree.
//otherwise the whole branch starting from this node will
//be discarded from XCFWTree.
if ( obj )
{
CleanupStack::PushL( obj );
factory->InitializeObjectL( *this );
if ( !iCurrentTreeNode )
{
//Adding root.
iCurrentTreeNode = iTree->AddNodeL( obj );
}
else
{
//add under certain parent.
iCurrentTreeNode = iTree->AddNodeL( obj, iCurrentTreeNode );
}
CleanupStack::Pop( obj );
}
else
{
//Notify observer about unknown data if current node is an element node
if ( iCurrentXMLNode->NodeType() == CMDXMLNode::EElementNode )
{
iObserver->HandleEngineErrorL( KErrUnknown );
}
// discard this branch in tree: loop out to next sibling of
// this node or its parent
while ( iCurrentXMLNode && !iCurrentXMLNode->NextSibling() )
{
iCurrentXMLNode = iCurrentXMLNode->ParentNode();
if ( iCurrentXMLNode && iCurrentTreeNode->Parent() )
{
iCurrentTreeNode = iCurrentTreeNode->Parent();
}
}
// set next node pointer to process
if( iCurrentXMLNode && iCurrentXMLNode->NextSibling() )
{
iCurrentXMLNode = iCurrentXMLNode->NextSibling();
}
}
}
// -----------------------------------------------------------------------------
// CXCFWEngine::DOM2TreeNextCycleL
// XML DOM is traversed node by node, and elements are added to content tree.
// Each call leaves will set iCurrentXMLNode to point to the next DOM node to
// be processed until there's no more nodes.
// -----------------------------------------------------------------------------
//
void CXCFWEngine::DOM2TreeNextCycleL()
{
CMDXMLNode* reference = NULL;
if ( iCurrentXMLNode )
{
reference = iCurrentXMLNode;
//add this XML node data to content tree
AddCurrentXMLNodeToTreeL();
// if node was discareded for some reason, let's keep calling
// until a node is accepted.
while ( iCurrentXMLNode && iCurrentXMLNode != reference )
{
reference = iCurrentXMLNode;
AddCurrentXMLNodeToTreeL();
}
if ( !iCurrentXMLNode )
{
return;
}
//if this node has children, go to first child now
if ( iCurrentXMLNode->FirstChild() )
{
iCurrentXMLNode = iCurrentXMLNode->FirstChild();
}
else //no children
{
//update XCFWTree parent node pointer as this xml node had no child
if ( iCurrentTreeNode && iCurrentTreeNode->Parent() )
{
iCurrentTreeNode = iCurrentTreeNode->Parent();
}
//if there's siblings at the same level, go to next sibling
if ( iCurrentXMLNode->NextSibling() )
{
iCurrentXMLNode = iCurrentXMLNode->NextSibling();
}
else //no siblings left
{
// get back in the tree to a level that has still siblings left
while ( iCurrentXMLNode && !iCurrentXMLNode->NextSibling() )
{
iCurrentXMLNode = iCurrentXMLNode->ParentNode();
// update XCFWTree parent pointer if necessary
if ( iCurrentXMLNode &&
iCurrentTreeNode && iCurrentTreeNode->Parent() )
{
iCurrentTreeNode = iCurrentTreeNode->Parent();
}
}
// now we're either at a level that has siblings, or then
// we're out of nodes. If there's a sibling, we'll process
// that next
if( iCurrentXMLNode && iCurrentXMLNode->NextSibling() )
{
iCurrentXMLNode = iCurrentXMLNode->NextSibling();
}
}
}
}
}
// -----------------------------------------------------------------------------
// CXCFWEngine::CurrentState()
// Returns engine's internal state. Client may want to know this at error
// situations to determine if a retry would be necessary.
// -----------------------------------------------------------------------------
//
EXPORT_C CXCFWEngine::TXCFWEngineState CXCFWEngine::CurrentState()
{
//If the last state change was by an error, return the state that
//engine was in when error occurred (error routine will set the state to
//EStateIdle). Otherwise return the current state.
if ( iStateByLastError != EStateIdle )
{
return iStateByLastError;
}
else
{
return iState;
}
}
// -----------------------------------------------------------------------------
// CXCFWEngine::ComposeFileCompleteL()
// Called by GMXML composer when DOM has been saved to file.
// Possible fatal errors are sent forward to XCFW client. Otherwise the client
// is just informed with saving completed event.
// -----------------------------------------------------------------------------
//
void CXCFWEngine::ComposeFileCompleteL()
{
//see if we have urecoverable errors from GMXML => if error severity is
//fatal, let's not go any further in processing.
if ( iComposer->ErrorSeverity() == EXMLFatal )
{
TInt err = iComposer->Error();
iStateByLastError = iState;
iState = EStateIdle;
FreeResources();
iObserver->HandleEngineErrorL( err );
}
else
{
FreeResources();
iObserver->HandleEngineEventL(
MXCFWEngineObserver::EEvtSavingComplete );
}
}
// -----------------------------------------------------------------------------
// CXCFWEngine::Tree2DOMNextCycleLL
// XCFWTree is traversed node by node, and elements are added to XML DOM.
// Each call leaves will set iCurrentTreeNode to point to the next node to
// be processed until there's no more nodes left in XCFW Tree.
// -----------------------------------------------------------------------------
//
void CXCFWEngine::Tree2DOMNextCycleL()
{
MXCFWNode* reference = NULL;
if ( iCurrentTreeNode )
{
reference = iCurrentTreeNode;
//add this tree node data to DOM
AddCurrentTreeNodeToDOML();
// if node was discareded for some reason, let's keep calling
// until a node is accepted.
while ( iCurrentTreeNode && iCurrentTreeNode != reference )
{
reference = iCurrentTreeNode;
AddCurrentTreeNodeToDOML();
}
if ( !iCurrentTreeNode )
{
return;
}
//if this node has children, go to first child now
if ( iCurrentTreeNode->FirstChild() )
{
iCurrentTreeNode = iCurrentTreeNode->FirstChild();
}
else //no children
{
//update DOM parent node pointer as this Tree node had no child
if ( iCurrentXMLNode && iCurrentXMLNode->ParentNode() )
{
iCurrentXMLNode = iCurrentXMLNode->ParentNode();
}
//if there's siblings at the same level, go to next sibling
if ( iCurrentTreeNode->NextSibling() )
{
iCurrentTreeNode = iCurrentTreeNode->NextSibling();
}
else //no siblings left
{
// get back in the tree to a level that has still siblings left
while ( iCurrentTreeNode && !iCurrentTreeNode->NextSibling() )
{
iCurrentTreeNode = iCurrentTreeNode->Parent();
// update DOM parent pointer if necessary
if ( iCurrentTreeNode &&
iCurrentXMLNode && iCurrentXMLNode->ParentNode() )
{
iCurrentXMLNode = iCurrentXMLNode->ParentNode();
}
}
// now we're either at a level that has siblings, or then
// we're out of nodes. If there's a sibling, we'll process
// that next
if( iCurrentTreeNode && iCurrentTreeNode->NextSibling() )
{
iCurrentTreeNode = iCurrentTreeNode->NextSibling();
}
}
}
}
}
// -----------------------------------------------------------------------------
// CXCFWEngine::AddCurrentTreeNodeToDOML
// New XML DOM element node is generated out of the XCFW Tree node data.
// DOM node data is queried from XCFW Tree node using the corresponding
// object factory. If registered object factory recognizes this node's typeid,
// default factory implementation is used.
// New XML Element node is added to XML DOM.
// -----------------------------------------------------------------------------
//
void CXCFWEngine::AddCurrentTreeNodeToDOML()
{
__ASSERT_LEAVE( iTree && iCurrentTreeNode, KErrGeneral );
CGECOObjectBase* obj = iCurrentTreeNode->Data();
CGECOObjectFactoryBase* factory = NULL;
TInt count = iFactoryList.Count();
TInt err = KErrNotSupported;
//Find factory for the current tree node
if ( count > 0 )
{
//loop through factories starting from the most recently added
//until a factory returns KErrNone for SetContext or we run out
//of factories
for ( TInt i = count-1 ; i>= 0 && KErrNone != err ; i--)
{
//Query factory for object
factory = iFactoryList[i];
err = factory->SetContext( obj );
}
}
// if none of the user factories recognized this object,
// use default factory.
if ( KErrNone != err )
{
factory = iDefaultFactory;
err = factory->SetContext( obj );
}
//if we have an object, let's add it to tree.
//otherwise the whole branch starting from this node will
//be discarded from XCFWTree.
if ( err == KErrNone )
{
CMDXMLElement* node = CMDXMLElement::NewLC(
ETrue, iXMLDoc, obj->TypeIdentifier() );
TInt counter = factory->NumAttributes() - 1;
while ( counter >= 0 )
{
TPtrC attrname;
TPtrC attrvalue;
HBufC* ebuf = NULL;
factory->AttributeDetailsL( counter, attrname, attrvalue );
node->SetAttributeL( attrname, attrvalue, ETrue );
if ( ebuf )
{
CleanupStack::PopAndDestroy( ebuf );
}
counter--;
}
//if object has text data, let's put it to a child node...
if ( factory->HasTextData() )
{
CMDXMLText* textnode = CMDXMLText::NewLC( iXMLDoc );
TPtrC text;
TBool locstatus;
factory->TextDetailsL( text, locstatus );
HBufC* ebuf = NULL;
//Check localization
if ( locstatus && iLocalizer )
{
TPtrC eref;
if ( KErrNone == iLocalizer->TextToEntityRef( text, eref ) )
{
ebuf = HBufC::NewLC( eref.Length() + KExtraChars );
ebuf->Des().Copy( KXCFWAnd );
ebuf->Des().Append( eref );
ebuf->Des().Append( KXCFWSemiC );
text.Set( ebuf->Des() );
}
}
textnode->SetDataL( text );
node->AppendChild( textnode );
//destroying entity ref buffer is safe now
if ( ebuf )
{
CleanupStack::PopAndDestroy( ebuf );
}
CleanupStack::Pop( textnode );
}
if ( !iCurrentXMLNode )
{
iXMLDoc->DocumentElement()->AppendChild(node);
}
else
{
iCurrentXMLNode->AppendChild( node );
}
iCurrentXMLNode = node;
CleanupStack::Pop( node );
}
else
{
//Notify observer about unknown data
iObserver->HandleEngineErrorL( KErrUnknown );
// discard this branch in tree: loop out to next sibling of
// this node or its parent
while ( iCurrentTreeNode && !iCurrentTreeNode->NextSibling() )
{
iCurrentTreeNode = iCurrentTreeNode->Parent();
if ( iCurrentTreeNode && iCurrentXMLNode->ParentNode() )
{
iCurrentXMLNode = iCurrentXMLNode->ParentNode();
}
}
// set next node pointer to process
if( iCurrentTreeNode && iCurrentTreeNode->NextSibling() )
{
iCurrentTreeNode = iCurrentTreeNode->NextSibling();
}
}
}
// -----------------------------------------------------------------------------
// CXCFWEngine::FreeResources
// XML parser / composer resources are freed (DOM tree will be deleted from mem)
// File name buffers are freed.
// -----------------------------------------------------------------------------
//
void CXCFWEngine::FreeResources()
{
iState = EStateIdle;
iFileSystem.Close();
delete iParser;
iParser = NULL;
delete iComposer;
iComposer = NULL;
delete iFile;
iFile = NULL;
delete iDTD;
iDTD = NULL;
delete iXMLDoc;
iXMLDoc = NULL;
iCurrentXMLNode = NULL;
iCurrentTreeNode = NULL;
if ( iTree )
{
iTree->SetLocked( EFalse );
iTree = NULL;
}
}
// -----------------------------------------------------------------------------
// CXCFWEngine::PrepareEntityConverterL
// Localizer is created and DTD load is requested. Localizer will complete
// pending request when done => Engine's RunL will be called.
// -----------------------------------------------------------------------------
//
void CXCFWEngine::PrepareEntityConverterAndSetActiveL()
{
TRequestStatus *s = &iStatus;
delete iLocalizer;
iLocalizer = NULL;
iLocalizer = CXCFWLocalizer::NewL();
//If we have a DTD
if ( iDTD->Des().Compare( KNullDesC ) != 0 )
{
// delete possible previous localizer instance and create new.
// For performance reasons, it could be wise to first
// check if we're loading the same DTD as last time. This
// could be done at localizer side.
// Ask Localizer to load Entity references. Localizer will
// complete the request when ready.
SetActive();
TRAPD( err, iLocalizer->LoadDTDL( iDTD->Des(), iFileSystem, &iStatus) );
if ( KErrNone != err )
{
User::RequestComplete(s, KErrNone );
iObserver->HandleEngineErrorL( KErrDTDLoadFailed );
//Complete here, since localizer will not do it
delete iLocalizer;
iLocalizer = NULL;
}
}
else
{
SetActive();
User::RequestComplete( s, KErrNone );
}
}
// -----------------------------------------------------------------------------
// CXCFWEngine::PrepareDTDPathL()
// Function checks the XML DOM for doc type declaration and extracts the
// possible dtd file name from it. DTD path is then created out of
// XML file location + localization folder template + dtd name.
// CXCFWLocalizer will then complete the string with current language setting
// and search for the file using language downgrade path if necessary.
// -----------------------------------------------------------------------------
//
void CXCFWEngine::PrepareDTDPathL()
{
//set up DTD if not already done
if ( iDTD && iXMLDoc && iDTD->Des().Compare ( KNullDesC ) == 0 )
{
//check if we have a dtd defined...
const TChar KQuote = '"';
const TChar KBckSlash = '\\';
TInt extStart = iXMLDoc->DocTypeTag().Find( KDTDExt );
if ( extStart != KErrNotFound )
{
if ( iXMLDoc->DocTypeTag().Find ( KMmsDTD ) != KErrNotFound )
{
iXMLDoc->SetDocTypeTagL( KDocTypeDeclNoDTD );
}
else
{
TInt delim = iXMLDoc->DocTypeTag().Left( extStart ).
LocateReverse( KQuote ) + 1;
TInt bsdelim = iXMLDoc->DocTypeTag().Left( extStart).
LocateReverse ( KBckSlash ) + 1;
delim = (bsdelim>delim)?bsdelim:delim;
if ( delim != KErrNotFound )
{
TInt dtdnamelen = extStart - delim + KDTDExtLen;
TInt pathlen = iFile->Des().LocateReverse ( KBckSlash );
delete iDTD;
iDTD = NULL;
iDTD = HBufC::NewL( pathlen + dtdnamelen + KLocFormatLen );
iDTD->Des().Copy( iFile->Des().Left( pathlen ) );
iDTD->Des().Append( KBckSlash );
iDTD->Des().Append( KLocFormat );
iDTD->Des().Append ( iXMLDoc->DocTypeTag().
Mid( delim, dtdnamelen ) );
}
}
}
}
if ( iDTD )
{
//Store DTD name to tree, so it is available at save.
iTree->SetDTDNameL( iDTD->Des() );
}
}
// End of File