/** 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 countconst 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; }// DestructorEXPORT_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 ); CleanupStack::Pop( obj ); if ( !iCurrentTreeNode ) { //Adding root. iCurrentTreeNode = iTree->AddNodeL( obj ); } else { //add under certain parent. iCurrentTreeNode = iTree->AddNodeL( obj, iCurrentTreeNode ); } } 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