xcfw/src/xcfwengine.cpp
author jake
Tue, 13 Apr 2010 15:07:27 +0300
branchv5backport
changeset 56 7b5c31fac191
parent 3 ff572005ac23
child 74 edd621764147
permissions -rw-r--r--
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