xml/xmlfw/src/xmlframework/parserimpl.cpp
changeset 0 e35f40988205
equal deleted inserted replaced
-1:000000000000 0:e35f40988205
       
     1 // Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include <ecom/ecom.h>
       
    17 
       
    18 #include <xml/contentprocessor.h>
       
    19 #include <xml/contenthandler.h>
       
    20 #include <xml/matchdata.h>
       
    21 #include <xml/stringdictionarycollection.h>
       
    22 #include <xml/xmlframeworkconstants.h>
       
    23 #include <xml/xmlframeworkerrors.h>
       
    24 #include "XmlFrameworkPanics.h"
       
    25 #include <xml/plugins/charsetconverter.h>
       
    26 #include <xml/plugins/contentprocessorinitparams.h>
       
    27 #include <xml/plugins/parserinitparams.h>
       
    28 #include <xml/plugins/parserinterface.h>
       
    29 
       
    30 #include "parserimpl.h"
       
    31 
       
    32 /** 
       
    33 Indicates the custom resolver implementation for XML parser framework. 
       
    34 
       
    35 @internalComponent
       
    36 */
       
    37 const TUid KCustomResolverUid			= {0x10273862};
       
    38 
       
    39 using namespace Xml;
       
    40 
       
    41 void TParserImpl::DestroyContentProcessorPtrMapping(TAny* aPtr)
       
    42 /**
       
    43 Tidy memory associated with this object.
       
    44 
       
    45 @param				aPtr The ContentProcessor pointer.
       
    46 
       
    47 */
       
    48 	{
       
    49 	TDtorContentProcessorPtrMapping* ptr = static_cast<TDtorContentProcessorPtrMapping*>(aPtr);
       
    50 	 
       
    51 	if (ptr->iDtorKey != KNullUid && ptr->iContentProcessor)
       
    52 		{
       
    53 		// Tell ECom to destroy its plugin details
       
    54 		REComSession::DestroyedImplementation(ptr->iDtorKey);
       
    55 
       
    56 		// Free memory
       
    57 		ptr->iContentProcessor->Release();
       
    58 		}
       
    59 
       
    60 	delete (ptr);
       
    61 	}
       
    62 
       
    63 
       
    64 
       
    65 TParserImpl::TParserImpl()
       
    66 /**
       
    67 Default constructor
       
    68 
       
    69 @post				This object is properly constructed.
       
    70 
       
    71 */
       
    72 :	iParser(NULL),
       
    73 	iCharSetConverter(NULL),
       
    74 	iStringDictionaryCollection(NULL)
       
    75 	{
       
    76 	
       
    77 	}
       
    78 
       
    79 
       
    80 
       
    81 void TParserImpl::OpenL(const CMatchData& aCriteria, MContentHandler& aCallback) 
       
    82 /**
       
    83 This method opens and sets all the objects contents.
       
    84 The StringDictionaryCollection is created and Opened.
       
    85 
       
    86 @pre				The object has just been constructed and no other values have been set.
       
    87 @post				The objects members have been set to the values given.
       
    88 
       
    89 @param				aCriteria Detailed criteria for parser resolution.
       
    90 @param				aCallback client to pass data to.
       
    91 
       
    92 */
       
    93 	{
       
    94 	Close();
       
    95 
       
    96 	if (!iCharSetConverter)
       
    97 		iCharSetConverter = CCharSetConverter::NewL();
       
    98 
       
    99 	if (!iStringDictionaryCollection)
       
   100 		{
       
   101 		iStringDictionaryCollection = new(ELeave) RStringDictionaryCollection();
       
   102 		iStringDictionaryCollection->OpenL();
       
   103 		}
       
   104 	
       
   105 	//verify mime type 
       
   106 	if (aCriteria.MimeType() != KNullDesC8)
       
   107 		{
       
   108 		// Create and remember the current mime type
       
   109 		iCurrentParserMatchData = aCriteria;
       
   110 		}
       
   111 	else
       
   112 		User::Leave(KErrArgument);
       
   113 
       
   114 	iDefParserMatchData = aCriteria;
       
   115 	iParser = ConstructParserL(aCriteria, aCallback);
       
   116 	iClient = &aCallback;
       
   117 	}
       
   118 
       
   119 
       
   120 void TParserImpl::Close()
       
   121 /**
       
   122 This method cleans up the object before destruction. It releases all resources in
       
   123 accordance to the R Class pattern.
       
   124 
       
   125 The framework will Close the StringDictionaryCollection and if owned will
       
   126 delete it.
       
   127 
       
   128 @post				This object may be allowed to go out of scope.
       
   129 
       
   130 */
       
   131 	{
       
   132 	// Close any remaining RStrings owned by iElementStack. This will prevent a
       
   133 	// memory leak from occuring when parsing a document that is not complete AND
       
   134 	// ParseEndL is NOT called before destroying the CParser object.
       
   135 	for (TInt i=0;i<iElementStack.Count();i++)
       
   136 		iElementStack[i].Close();
       
   137 	
       
   138 	iElementStack.Close();
       
   139 
       
   140 	// Destroy the chain of plugins
       
   141 	DestroyChain();
       
   142 	
       
   143 	if (iParser)
       
   144 		{
       
   145 		// Delete the Parser
       
   146 		REComSession::DestroyedImplementation(iParserDtorKey);
       
   147 
       
   148 		iParser->Release();
       
   149 		iParser = NULL;
       
   150 		}
       
   151 
       
   152 	delete iCharSetConverter;
       
   153 	iCharSetConverter = NULL;
       
   154 			
       
   155 	if (iStringDictionaryCollection)
       
   156 		{
       
   157 		iStringDictionaryCollection->Close();
       
   158 		delete iStringDictionaryCollection;
       
   159 		iStringDictionaryCollection = NULL;
       
   160 		}
       
   161 
       
   162 	iClient = NULL;
       
   163 
       
   164 	REComSession::FinalClose();
       
   165 	}
       
   166 
       
   167 
       
   168 void TParserImpl::ParseChunkL(const TDesC8& aChunk)
       
   169 /**
       
   170 This method starts the parser parsing a descriptor.
       
   171 The descriptor does not contain the last part of the document. 
       
   172 
       
   173 @pre				OpenL has been called
       
   174 
       
   175 @param				aChunk the chunk to parse - not the last chunk
       
   176 
       
   177 */
       
   178 	{
       
   179 	iParser->ParseChunkL(aChunk);
       
   180 	}
       
   181 
       
   182 
       
   183 void TParserImpl::ParseLastChunkL(const TDesC8& aFinalChunk)
       
   184 /**
       
   185 This method starts the parser parsing a descriptor.
       
   186 The descriptor contains the last part of the document. 
       
   187 
       
   188 @pre				OpenL has been called
       
   189 
       
   190 @param				aFinalChunk the final chunk to parse
       
   191 
       
   192 */
       
   193 	{		
       
   194 	iParser->ParseLastChunkL(aFinalChunk);
       
   195 	}
       
   196 
       
   197 
       
   198 void TParserImpl::SetContentHandler(MContentHandler& aCallback)
       
   199 /**
       
   200 Allows the user to set/change the client for this parse session.
       
   201 
       
   202 @pre				OpenL has been called
       
   203 
       
   204 @param				aCallback the client at the end of the callback
       
   205 					chain that is to receive the parsed document information.
       
   206 
       
   207 */
       
   208 	{
       
   209 	iClient = &aCallback;
       
   210 	
       
   211 	MContentSource* prev;
       
   212 	if (iDtorKeyAndPluginList.Count())
       
   213 		{
       
   214 		// set the last plugin to point to the client
       
   215 		prev = iDtorKeyAndPluginList[iDtorKeyAndPluginList.Count()-1]->iContentProcessor;
       
   216 		}
       
   217 	else
       
   218 		{
       
   219 		// set the parser to point to the client as there is no chain
       
   220 		prev = iParser;
       
   221 		}
       
   222 	prev->SetContentSink(*iClient);
       
   223 	}
       
   224 	
       
   225 	
       
   226 	
       
   227 void TParserImpl::SetProcessorChainL(const RContentProcessorUids& aPlugins)
       
   228 /**
       
   229 Allows the user to change the client and set the plugin chain for 
       
   230 this parse session.
       
   231 
       
   232 @pre				OpenL has been called
       
   233 
       
   234 @param				aCallback the client at the end of the callback
       
   235 					chain that is to receive the parsed document information.
       
   236 @param				aPlugins a list of plugin implementation uids that
       
   237 					make up the callback chain.
       
   238 
       
   239 */
       
   240 	{
       
   241 	// If there is an existing chain delete all but the parser
       
   242 	DestroyChain();
       
   243 	
       
   244 	// Rebuild the chain.
       
   245 	MContentHandler* callback = BuildChainL(*iClient, aPlugins);
       
   246 	
       
   247 	iParser->SetContentSink(*callback);
       
   248 	}
       
   249 	
       
   250 
       
   251 void TParserImpl::ResetMimeTypeL()
       
   252 	{
       
   253 	
       
   254 	if ( !(iCurrentParserMatchData == iDefParserMatchData) )
       
   255 		{
       
   256 		SetMimeTypeL(iDefParserMatchData);
       
   257 		}
       
   258 	}
       
   259 	
       
   260 
       
   261 void TParserImpl::SetMimeTypeL(const CMatchData& aCriteria)
       
   262 /**
       
   263 Allows the user to set/change the parser mime type used for 
       
   264 this parse session.
       
   265 
       
   266 @pre				OpenL has been called
       
   267 
       
   268 @param				aParserMimeType the mime type of the requested parser
       
   269 
       
   270 */
       
   271 	{
       
   272 	// Check if we are already using this parser
       
   273 	if (aCriteria == iCurrentParserMatchData)
       
   274 		{
       
   275 		// There is no change to the parser. 
       
   276 		return;
       
   277 		}
       
   278 
       
   279 	// Delete the Parser
       
   280 	if (iParser)
       
   281 		{
       
   282 		REComSession::DestroyedImplementation(iParserDtorKey);
       
   283 		iParser->Release();
       
   284 		iParser = NULL;
       
   285 		}
       
   286 
       
   287 	MContentHandler* next;
       
   288 	if (iDtorKeyAndPluginList.Count())
       
   289 		{
       
   290 		// point the parser to the first plugin in the chain
       
   291 		next = iDtorKeyAndPluginList[0]->iContentProcessor;
       
   292 		}
       
   293 	else
       
   294 		{
       
   295 		// point the parser to the client as there is no chain
       
   296 		next = iClient;
       
   297 		}
       
   298 	// Create the new parser and point to the next plugin
       
   299 	iParser = ConstructParserL(aCriteria, *next);
       
   300 	
       
   301 	// Remember what parser we are using.
       
   302 	iCurrentParserMatchData = aCriteria;
       
   303 	}
       
   304 	
       
   305 	
       
   306 TInt TParserImpl::EnableFeature(TInt aParserFeature)
       
   307 	{
       
   308 	__ASSERT_ALWAYS(iParser, Panic(EXmlFrameworkPanicUnexpectedLogic));
       
   309 
       
   310 	return iParser->EnableFeature(aParserFeature);
       
   311 	}
       
   312 
       
   313 TInt TParserImpl::DisableFeature(TInt aParserFeature)
       
   314 	{
       
   315 	__ASSERT_ALWAYS(iParser, Panic(EXmlFrameworkPanicUnexpectedLogic));
       
   316 
       
   317 	return iParser->DisableFeature(aParserFeature);
       
   318 	}
       
   319 
       
   320 TBool TParserImpl::IsFeatureEnabled(TInt aParserFeature) const
       
   321 	{
       
   322 	__ASSERT_ALWAYS(iParser, Panic(EXmlFrameworkPanicUnexpectedLogic));
       
   323 
       
   324 	return iParser->IsFeatureEnabled(aParserFeature);
       
   325 	}
       
   326 
       
   327 
       
   328 void TParserImpl::AddPreloadedDictionaryL(const TDesC8& aPublicId)
       
   329 	{
       
   330 	iStringDictionaryCollection->OpenDictionaryL(aPublicId);   
       
   331 	}
       
   332 
       
   333 
       
   334 RStringPool& TParserImpl::StringPool()
       
   335 	{
       
   336 	return iStringDictionaryCollection->StringPool();
       
   337 	}
       
   338 
       
   339 
       
   340 RStringDictionaryCollection& TParserImpl::StringDictionaryCollection()
       
   341 	{
       
   342 	return *iStringDictionaryCollection;
       
   343 	}
       
   344 
       
   345 
       
   346 MContentHandler* TParserImpl::BuildChainL(MContentHandler& aCallback, 
       
   347 										  const RContentProcessorUids& aPlugins)
       
   348 /**
       
   349 This method builds the chain of plugins, so that information may flow down
       
   350 the chain.
       
   351 
       
   352 The first in the chain is the parser, the last is the client.
       
   353 
       
   354 @param				aCallback client to pass data to.
       
   355 @param				aPlugins the list of plugins in the chain.
       
   356 
       
   357 @return				the first plugin in the chain. If there is no chain
       
   358 					the client is returned.
       
   359 
       
   360 */
       
   361 	{
       
   362 	// Start with the last plugin first and point it to the callback passed.
       
   363 	// Then work you way up the chain, ending with the Parser calling the first plugin.
       
   364 
       
   365 	TInt count = aPlugins.Count();
       
   366     MContentHandler* callback = &aCallback;
       
   367 
       
   368 	while (count>0)
       
   369 		{
       
   370 		callback = ConstructPluginInReverseL(aPlugins[--count], *callback);
       
   371 		}
       
   372 
       
   373 	return (callback);
       
   374 	}
       
   375 
       
   376 
       
   377 
       
   378 void TParserImpl::DestroyChain()
       
   379 /**
       
   380 
       
   381 Destroys the client and the chain of plugins not including the parser.
       
   382 
       
   383 @post				The chain and client are destroyed and parsing
       
   384 					cannot take place.
       
   385 */
       
   386 	{
       
   387 	TInt count = iDtorKeyAndPluginList.Count();
       
   388 	while (count)
       
   389 		{
       
   390 		DestroyContentProcessorPtrMapping(iDtorKeyAndPluginList[--count]);
       
   391 		}
       
   392 	iDtorKeyAndPluginList.Reset();
       
   393 	}
       
   394 
       
   395 
       
   396 MParser* TParserImpl::ConstructParserL(const CMatchData& aCriteria, 
       
   397 							   		   MContentHandler& aCallback)
       
   398 /**
       
   399 This method constructs a MParser derived object.
       
   400 
       
   401 @return				A pointer to the parser found.
       
   402 @leave				KErrXmlParserPluginNotFound If ECom fails to find 
       
   403 					the object a leave occurs.
       
   404 @leave				KErrArgument If CMatchData is lacking mandatory mime type field.
       
   405 
       
   406 @param				aCriteria Detailed criteria for parser resolution.
       
   407 @param				aCallback client to pass data to.
       
   408 
       
   409 */
       
   410 	{
       
   411 	TInt err;
       
   412 	HBufC8* stream = NULL;
       
   413 	
       
   414 	// Check entry criteria
       
   415 	if (aCriteria.MimeType() == KNullDesC8)
       
   416 		{
       
   417 		User::Leave(KErrArgument);
       
   418 		}
       
   419 		
       
   420 	// Set resolving parameters to find a plug-in with a matching parser
       
   421 	TEComResolverParams resolverParams;
       
   422 	resolverParams.SetWildcardMatch(ETrue);
       
   423 	stream = aCriteria.PackToBufferL();
       
   424 	CleanupStack::PushL(stream);
       
   425 	resolverParams.SetDataType(*stream);
       
   426 	
       
   427 	// Package up the parameters to pass
       
   428 	TParserInitParams initParams;
       
   429 	initParams.iCharSetConverter = iCharSetConverter;
       
   430 	initParams.iContentHandler = &aCallback;
       
   431 	initParams.iStringDictionaryCollection = iStringDictionaryCollection;
       
   432 	initParams.iElementStack = &iElementStack;
       
   433 
       
   434 	// do this for now until I work out what to do with the other params
       
   435 	TAny* any = NULL;
       
   436 	TRAP(err, any = REComSession::CreateImplementationL(KParserInterfaceUid,
       
   437 													iParserDtorKey, 
       
   438 													(TAny*)&initParams, 
       
   439 													resolverParams,
       
   440 													KCustomResolverUid));
       
   441 	CleanupStack::PopAndDestroy(stream);
       
   442 	if (err != KErrNone)
       
   443 		{
       
   444 		if (err == KErrNotFound)
       
   445 			{
       
   446 			User::Leave(KErrXmlParserPluginNotFound);
       
   447 			}
       
   448 		User::Leave(err);
       
   449 		}
       
   450 	
       
   451 	MParser* object = static_cast<MParser*>(any);
       
   452 	return object;
       
   453 	}
       
   454 	
       
   455 MContentProcessor* TParserImpl::ConstructPluginInReverseL(const TUid& aImplementationUid, 
       
   456 														 MContentHandler& aCallback)
       
   457 /**
       
   458 This method constructs a CContentProcessor and places it in reverse order in the chain.
       
   459 
       
   460 @return				A pointer to the plugin found.
       
   461 @leave				KErrXmlPluginNotFound If ECom fails to find 
       
   462 					the object a leave occurs.
       
   463 
       
   464 @param				aImplementationUid The implementation uid of the plugin.
       
   465 @param				aCallback client to pass data to.
       
   466 
       
   467 */
       
   468 	{
       
   469 	TDtorContentProcessorPtrMapping* mapping = new(ELeave) TDtorContentProcessorPtrMapping;
       
   470 	mapping->iDtorKey = KNullUid;
       
   471 	mapping->iContentProcessor = NULL;
       
   472 
       
   473 	CleanupStack::PushL(TCleanupItem(DestroyContentProcessorPtrMapping, mapping));
       
   474 	
       
   475 	// Package up the parameters to pass
       
   476 	TContentProcessorInitParams initParams;
       
   477 	initParams.iContentHandler = &aCallback;
       
   478 	initParams.iStringDictionaryCollection = iStringDictionaryCollection;
       
   479 	initParams.iElementStack = &iElementStack;
       
   480 
       
   481 	// Client knows specific implementation.
       
   482 	// Pass the callback object of the next thing in the chain.
       
   483 	TAny* any = NULL;
       
   484 	
       
   485 	TRAPD(err, any = REComSession::CreateImplementationL(aImplementationUid,
       
   486 														 mapping->iDtorKey,
       
   487 														 &initParams));
       
   488 													
       
   489 	if (err != KErrNone)
       
   490 		{
       
   491 		if (err == KErrNotFound)
       
   492 			{
       
   493 			User::Leave(KErrXmlPluginNotFound);
       
   494 			}
       
   495 
       
   496 		User::Leave(err);
       
   497 		}
       
   498 		
       
   499 	mapping->iContentProcessor = static_cast<MContentProcessor*>(any);
       
   500 
       
   501 	// We insert at the start as we are building the chain backwards, last till first.
       
   502 	User::LeaveIfError(iDtorKeyAndPluginList.Insert(mapping, 0));
       
   503 
       
   504 	CleanupStack::Pop(mapping);
       
   505 	return (mapping->iContentProcessor); 
       
   506 	}
       
   507 
       
   508 
       
   509 
       
   510