diff -r 000000000000 -r e35f40988205 xml/xmlfw/src/xmlframework/parserimpl.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xml/xmlfw/src/xmlframework/parserimpl.cpp Thu Dec 17 09:29:21 2009 +0200 @@ -0,0 +1,510 @@ +// Copyright (c) 2003-2009 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: +// + +#include + +#include +#include +#include +#include +#include +#include +#include "XmlFrameworkPanics.h" +#include +#include +#include +#include + +#include "parserimpl.h" + +/** +Indicates the custom resolver implementation for XML parser framework. + +@internalComponent +*/ +const TUid KCustomResolverUid = {0x10273862}; + +using namespace Xml; + +void TParserImpl::DestroyContentProcessorPtrMapping(TAny* aPtr) +/** +Tidy memory associated with this object. + +@param aPtr The ContentProcessor pointer. + +*/ + { + TDtorContentProcessorPtrMapping* ptr = static_cast(aPtr); + + if (ptr->iDtorKey != KNullUid && ptr->iContentProcessor) + { + // Tell ECom to destroy its plugin details + REComSession::DestroyedImplementation(ptr->iDtorKey); + + // Free memory + ptr->iContentProcessor->Release(); + } + + delete (ptr); + } + + + +TParserImpl::TParserImpl() +/** +Default constructor + +@post This object is properly constructed. + +*/ +: iParser(NULL), + iCharSetConverter(NULL), + iStringDictionaryCollection(NULL) + { + + } + + + +void TParserImpl::OpenL(const CMatchData& aCriteria, MContentHandler& aCallback) +/** +This method opens and sets all the objects contents. +The StringDictionaryCollection is created and Opened. + +@pre The object has just been constructed and no other values have been set. +@post The objects members have been set to the values given. + +@param aCriteria Detailed criteria for parser resolution. +@param aCallback client to pass data to. + +*/ + { + Close(); + + if (!iCharSetConverter) + iCharSetConverter = CCharSetConverter::NewL(); + + if (!iStringDictionaryCollection) + { + iStringDictionaryCollection = new(ELeave) RStringDictionaryCollection(); + iStringDictionaryCollection->OpenL(); + } + + //verify mime type + if (aCriteria.MimeType() != KNullDesC8) + { + // Create and remember the current mime type + iCurrentParserMatchData = aCriteria; + } + else + User::Leave(KErrArgument); + + iDefParserMatchData = aCriteria; + iParser = ConstructParserL(aCriteria, aCallback); + iClient = &aCallback; + } + + +void TParserImpl::Close() +/** +This method cleans up the object before destruction. It releases all resources in +accordance to the R Class pattern. + +The framework will Close the StringDictionaryCollection and if owned will +delete it. + +@post This object may be allowed to go out of scope. + +*/ + { + // Close any remaining RStrings owned by iElementStack. This will prevent a + // memory leak from occuring when parsing a document that is not complete AND + // ParseEndL is NOT called before destroying the CParser object. + for (TInt i=0;iRelease(); + iParser = NULL; + } + + delete iCharSetConverter; + iCharSetConverter = NULL; + + if (iStringDictionaryCollection) + { + iStringDictionaryCollection->Close(); + delete iStringDictionaryCollection; + iStringDictionaryCollection = NULL; + } + + iClient = NULL; + + REComSession::FinalClose(); + } + + +void TParserImpl::ParseChunkL(const TDesC8& aChunk) +/** +This method starts the parser parsing a descriptor. +The descriptor does not contain the last part of the document. + +@pre OpenL has been called + +@param aChunk the chunk to parse - not the last chunk + +*/ + { + iParser->ParseChunkL(aChunk); + } + + +void TParserImpl::ParseLastChunkL(const TDesC8& aFinalChunk) +/** +This method starts the parser parsing a descriptor. +The descriptor contains the last part of the document. + +@pre OpenL has been called + +@param aFinalChunk the final chunk to parse + +*/ + { + iParser->ParseLastChunkL(aFinalChunk); + } + + +void TParserImpl::SetContentHandler(MContentHandler& aCallback) +/** +Allows the user to set/change the client for this parse session. + +@pre OpenL has been called + +@param aCallback the client at the end of the callback + chain that is to receive the parsed document information. + +*/ + { + iClient = &aCallback; + + MContentSource* prev; + if (iDtorKeyAndPluginList.Count()) + { + // set the last plugin to point to the client + prev = iDtorKeyAndPluginList[iDtorKeyAndPluginList.Count()-1]->iContentProcessor; + } + else + { + // set the parser to point to the client as there is no chain + prev = iParser; + } + prev->SetContentSink(*iClient); + } + + + +void TParserImpl::SetProcessorChainL(const RContentProcessorUids& aPlugins) +/** +Allows the user to change the client and set the plugin chain for +this parse session. + +@pre OpenL has been called + +@param aCallback the client at the end of the callback + chain that is to receive the parsed document information. +@param aPlugins a list of plugin implementation uids that + make up the callback chain. + +*/ + { + // If there is an existing chain delete all but the parser + DestroyChain(); + + // Rebuild the chain. + MContentHandler* callback = BuildChainL(*iClient, aPlugins); + + iParser->SetContentSink(*callback); + } + + +void TParserImpl::ResetMimeTypeL() + { + + if ( !(iCurrentParserMatchData == iDefParserMatchData) ) + { + SetMimeTypeL(iDefParserMatchData); + } + } + + +void TParserImpl::SetMimeTypeL(const CMatchData& aCriteria) +/** +Allows the user to set/change the parser mime type used for +this parse session. + +@pre OpenL has been called + +@param aParserMimeType the mime type of the requested parser + +*/ + { + // Check if we are already using this parser + if (aCriteria == iCurrentParserMatchData) + { + // There is no change to the parser. + return; + } + + // Delete the Parser + if (iParser) + { + REComSession::DestroyedImplementation(iParserDtorKey); + iParser->Release(); + iParser = NULL; + } + + MContentHandler* next; + if (iDtorKeyAndPluginList.Count()) + { + // point the parser to the first plugin in the chain + next = iDtorKeyAndPluginList[0]->iContentProcessor; + } + else + { + // point the parser to the client as there is no chain + next = iClient; + } + // Create the new parser and point to the next plugin + iParser = ConstructParserL(aCriteria, *next); + + // Remember what parser we are using. + iCurrentParserMatchData = aCriteria; + } + + +TInt TParserImpl::EnableFeature(TInt aParserFeature) + { + __ASSERT_ALWAYS(iParser, Panic(EXmlFrameworkPanicUnexpectedLogic)); + + return iParser->EnableFeature(aParserFeature); + } + +TInt TParserImpl::DisableFeature(TInt aParserFeature) + { + __ASSERT_ALWAYS(iParser, Panic(EXmlFrameworkPanicUnexpectedLogic)); + + return iParser->DisableFeature(aParserFeature); + } + +TBool TParserImpl::IsFeatureEnabled(TInt aParserFeature) const + { + __ASSERT_ALWAYS(iParser, Panic(EXmlFrameworkPanicUnexpectedLogic)); + + return iParser->IsFeatureEnabled(aParserFeature); + } + + +void TParserImpl::AddPreloadedDictionaryL(const TDesC8& aPublicId) + { + iStringDictionaryCollection->OpenDictionaryL(aPublicId); + } + + +RStringPool& TParserImpl::StringPool() + { + return iStringDictionaryCollection->StringPool(); + } + + +RStringDictionaryCollection& TParserImpl::StringDictionaryCollection() + { + return *iStringDictionaryCollection; + } + + +MContentHandler* TParserImpl::BuildChainL(MContentHandler& aCallback, + const RContentProcessorUids& aPlugins) +/** +This method builds the chain of plugins, so that information may flow down +the chain. + +The first in the chain is the parser, the last is the client. + +@param aCallback client to pass data to. +@param aPlugins the list of plugins in the chain. + +@return the first plugin in the chain. If there is no chain + the client is returned. + +*/ + { + // Start with the last plugin first and point it to the callback passed. + // Then work you way up the chain, ending with the Parser calling the first plugin. + + TInt count = aPlugins.Count(); + MContentHandler* callback = &aCallback; + + while (count>0) + { + callback = ConstructPluginInReverseL(aPlugins[--count], *callback); + } + + return (callback); + } + + + +void TParserImpl::DestroyChain() +/** + +Destroys the client and the chain of plugins not including the parser. + +@post The chain and client are destroyed and parsing + cannot take place. +*/ + { + TInt count = iDtorKeyAndPluginList.Count(); + while (count) + { + DestroyContentProcessorPtrMapping(iDtorKeyAndPluginList[--count]); + } + iDtorKeyAndPluginList.Reset(); + } + + +MParser* TParserImpl::ConstructParserL(const CMatchData& aCriteria, + MContentHandler& aCallback) +/** +This method constructs a MParser derived object. + +@return A pointer to the parser found. +@leave KErrXmlParserPluginNotFound If ECom fails to find + the object a leave occurs. +@leave KErrArgument If CMatchData is lacking mandatory mime type field. + +@param aCriteria Detailed criteria for parser resolution. +@param aCallback client to pass data to. + +*/ + { + TInt err; + HBufC8* stream = NULL; + + // Check entry criteria + if (aCriteria.MimeType() == KNullDesC8) + { + User::Leave(KErrArgument); + } + + // Set resolving parameters to find a plug-in with a matching parser + TEComResolverParams resolverParams; + resolverParams.SetWildcardMatch(ETrue); + stream = aCriteria.PackToBufferL(); + CleanupStack::PushL(stream); + resolverParams.SetDataType(*stream); + + // Package up the parameters to pass + TParserInitParams initParams; + initParams.iCharSetConverter = iCharSetConverter; + initParams.iContentHandler = &aCallback; + initParams.iStringDictionaryCollection = iStringDictionaryCollection; + initParams.iElementStack = &iElementStack; + + // do this for now until I work out what to do with the other params + TAny* any = NULL; + TRAP(err, any = REComSession::CreateImplementationL(KParserInterfaceUid, + iParserDtorKey, + (TAny*)&initParams, + resolverParams, + KCustomResolverUid)); + CleanupStack::PopAndDestroy(stream); + if (err != KErrNone) + { + if (err == KErrNotFound) + { + User::Leave(KErrXmlParserPluginNotFound); + } + User::Leave(err); + } + + MParser* object = static_cast(any); + return object; + } + +MContentProcessor* TParserImpl::ConstructPluginInReverseL(const TUid& aImplementationUid, + MContentHandler& aCallback) +/** +This method constructs a CContentProcessor and places it in reverse order in the chain. + +@return A pointer to the plugin found. +@leave KErrXmlPluginNotFound If ECom fails to find + the object a leave occurs. + +@param aImplementationUid The implementation uid of the plugin. +@param aCallback client to pass data to. + +*/ + { + TDtorContentProcessorPtrMapping* mapping = new(ELeave) TDtorContentProcessorPtrMapping; + mapping->iDtorKey = KNullUid; + mapping->iContentProcessor = NULL; + + CleanupStack::PushL(TCleanupItem(DestroyContentProcessorPtrMapping, mapping)); + + // Package up the parameters to pass + TContentProcessorInitParams initParams; + initParams.iContentHandler = &aCallback; + initParams.iStringDictionaryCollection = iStringDictionaryCollection; + initParams.iElementStack = &iElementStack; + + // Client knows specific implementation. + // Pass the callback object of the next thing in the chain. + TAny* any = NULL; + + TRAPD(err, any = REComSession::CreateImplementationL(aImplementationUid, + mapping->iDtorKey, + &initParams)); + + if (err != KErrNone) + { + if (err == KErrNotFound) + { + User::Leave(KErrXmlPluginNotFound); + } + + User::Leave(err); + } + + mapping->iContentProcessor = static_cast(any); + + // We insert at the start as we are building the chain backwards, last till first. + User::LeaveIfError(iDtorKeyAndPluginList.Insert(mapping, 0)); + + CleanupStack::Pop(mapping); + return (mapping->iContentProcessor); + } + + + +