diff -r 000000000000 -r 79c6a41cd166 xcfw/src/xcfwengine.cpp --- /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 +#include +#include +#include +#include +#include +#include + +// CONSTANTS +// default XML declaration +_LIT( KXMLDeclaration, ""); +// default Doctype declaration +_LIT( KDocTypeDecl, ""); +_LIT( KDocTypeDeclNoDTD, ""); +_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 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