updated dependencies; compiles again (including all plugins) with winscw_udeb without error
/*
* 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