xml/xmlfw/src/xmlframework/parserimpl.cpp
changeset 0 e35f40988205
--- /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 <ecom/ecom.h>
+
+#include <xml/contentprocessor.h>
+#include <xml/contenthandler.h>
+#include <xml/matchdata.h>
+#include <xml/stringdictionarycollection.h>
+#include <xml/xmlframeworkconstants.h>
+#include <xml/xmlframeworkerrors.h>
+#include "XmlFrameworkPanics.h"
+#include <xml/plugins/charsetconverter.h>
+#include <xml/plugins/contentprocessorinitparams.h>
+#include <xml/plugins/parserinitparams.h>
+#include <xml/plugins/parserinterface.h>
+
+#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<TDtorContentProcessorPtrMapping*>(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;i<iElementStack.Count();i++)
+		iElementStack[i].Close();
+	
+	iElementStack.Close();
+
+	// Destroy the chain of plugins
+	DestroyChain();
+	
+	if (iParser)
+		{
+		// Delete the Parser
+		REComSession::DestroyedImplementation(iParserDtorKey);
+
+		iParser->Release();
+		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<MParser*>(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<MContentProcessor*>(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); 
+	}
+
+
+
+