xcfw/src/xcfwengine.cpp
changeset 0 79c6a41cd166
child 3 ff572005ac23
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xcfw/src/xcfwengine.cpp	Thu Dec 17 08:54:17 2009 +0200
@@ -0,0 +1,1390 @@
+/*
+* 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 ) );                
+                    }
+                }                
+            }
+        }
+    //Store DTD name to tree, so it is available at save.
+    iTree->SetDTDNameL( iDTD->Des() );
+    }
+
+//  End of File