--- /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