xml/xmlexpatparser/src/cexpat.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 <charconv.h>
       
    17 
       
    18 #include <xml/contenthandler.h>
       
    19 #include <xml/documentparameters.h>
       
    20 #include <xml/taginfo.h>
       
    21 #include <xml/xmlparsererrors.h>
       
    22 #include <xml/plugins/charsetconverter.h>
       
    23 
       
    24 #include "cexpat.h"
       
    25 
       
    26 using namespace Xml;
       
    27 
       
    28 const XML_Char KNamespaceSeparator = '!';
       
    29 const TInt KExpatHeapSize = 64*1024-256;
       
    30 
       
    31 LOCAL_C void AttributeArrayDelete(TAny *aPtr);
       
    32 
       
    33 /*
       
    34 aDebugFailCount is for testing only, to configure the parser heap to fail during CExpat construction.
       
    35 
       
    36 After construction CExpat::GetInternalHeap() can be used in conjunction with __RHEAP_FAILNEXT
       
    37 for out-of-memory testing.
       
    38 */
       
    39 CExpat* CExpat::NewL(MContentHandler& aContentHandler, RStringPool& aStringPool, CCharSetConverter& aCharSetConverter,
       
    40 					 RElementStack& aElementStack, TInt aDebugFailCount)
       
    41 	{
       
    42 	CExpat* self = new(ELeave) CExpat(aContentHandler, aStringPool, aCharSetConverter, aElementStack);
       
    43 
       
    44 	CleanupStack::PushL(self);
       
    45 	self->ConstructL(aDebugFailCount);
       
    46 	CleanupStack::Pop(self);
       
    47 
       
    48 	return self;
       
    49 	}
       
    50 
       
    51 CExpat::CExpat(MContentHandler& aContentHandler, RStringPool& aStringPool, CCharSetConverter& aCharSetConverter, 
       
    52 			   RElementStack& aElementStack) :
       
    53 	iContentHandler(&aContentHandler), iStringPool(aStringPool), iCharSetConverter(aCharSetConverter), 
       
    54 					iElementStack(aElementStack), iInputBuffer(0,0,0),
       
    55 	iPrevStatus(XML_STATUS_OK),
       
    56 	iPrevError(KErrNone)
       
    57 	{
       
    58 	}
       
    59 
       
    60 void CExpat::ConstructL(TInt aDebugFailCount)
       
    61 	{
       
    62 	iAllocator.ConstructL(KExpatHeapSize, aDebugFailCount);
       
    63 	ResetL();
       
    64 	}
       
    65 
       
    66 CExpat::~CExpat()
       
    67 	{
       
    68 	// iParser must be freed here.  The destructor of iAllocator (~TExpat) is called automatically
       
    69 	// when CExpat is destructed, as it is a member variable of CExpat.  *But* ~TExpat() will only close its heap
       
    70 	// which does not free any memory allocated on it.  So - we have to free the memory here, before
       
    71 	// deleting the allocator.  This memory is guaranteed to be freed here, before the heap is closed
       
    72 	// as the body of the destructor completes before the member destructors (~TExpat) are called.
       
    73 	if ( iParser )
       
    74 		{
       
    75 		XML_ParserFree( iParser );		
       
    76 		}
       
    77 	}
       
    78 
       
    79 /*
       
    80 ResetL resets an the parser or allocates one if none exists.  This could be the case for one of two reasons:
       
    81 
       
    82   1. This is called as part of the construction of CExpat
       
    83   2. A MContentHandler function left.  In this case the parser and all its memory will have been deleted.
       
    84 
       
    85 */
       
    86 void CExpat::ResetL()
       
    87 	{
       
    88 	iParseMode = EReportNamespaces | EReportNamespacePrefixes;
       
    89 	iBufferReady = EFalse;
       
    90 	
       
    91 	iPrevStatus = XML_STATUS_OK;
       
    92 	iPrevError = KErrNone;
       
    93 
       
    94 	if(iParser)
       
    95 		XML_ParserReset(iParser, NULL);
       
    96 	else
       
    97 		{
       
    98 		XML_Memory_Handling_Suite m;
       
    99 		iAllocator.FillAllocStruct(m);
       
   100 
       
   101 		// Expat element/attribute names are passed as a single string containing the prefix, uri and local part.
       
   102 		// This character is used to separate those three parts.
       
   103 		XML_Char sep[] = { KNamespaceSeparator, 0 };
       
   104 
       
   105 		iParser = XML_ParserCreate_MM(0, &m, sep);
       
   106 		User::LeaveIfNull(iParser);
       
   107 		}
       
   108 
       
   109 	// UserData is the first argument passed to us by all Expat callbacks
       
   110 	XML_SetUserData(iParser, this);
       
   111 
       
   112 	XML_SetElementHandler(iParser, StartElementHandlerL, EndElementHandlerL);
       
   113 	XML_SetCharacterDataHandler(iParser, CharacterDataHandlerL);
       
   114 	XML_SetProcessingInstructionHandler(iParser, ProcessingInstructionHandlerL);
       
   115 	XML_SetXmlDeclHandler(iParser, XmlDeclHandlerL);
       
   116 
       
   117 	XML_SetNamespaceDeclHandler(iParser, StartNamespaceDeclHandlerL, EndNamespaceDeclHandlerL);
       
   118 
       
   119 	// This tells Expat to pass all three parts of element/attribute names to us: prefix, uri and local part
       
   120 	XML_SetReturnNSTriplet(iParser, 1);
       
   121 
       
   122 	XML_SetSkippedEntityHandler(iParser, SkippedEntityHandlerL);
       
   123 	XML_SetExternalEntityRefHandler(iParser, ExternalEntityRefHandlerL);
       
   124 	}
       
   125 
       
   126 TDes8& CExpat::GetBufferL(TInt aLength)
       
   127 	{
       
   128 	TUint8* buf = (TUint8*) User::LeaveIfNull(XML_GetBuffer(iParser, aLength));
       
   129 
       
   130 	iInputBuffer.Set(buf, 0, aLength);
       
   131 
       
   132 	iBufferReady = ETrue;
       
   133 
       
   134 	return iInputBuffer;
       
   135 	}
       
   136 
       
   137 void CExpat::ParseL(TBool done)
       
   138 	{
       
   139 	// GetBufferL must be called before each call to this function
       
   140 	if(!iBufferReady)
       
   141 		User::Leave(KErrNotReady);
       
   142 
       
   143 	iBufferReady = EFalse;
       
   144 
       
   145 	XML_Status status = XML_STATUS_OK;
       
   146 	TInt error = KErrNone;
       
   147 
       
   148 	// Two forms of error come out of here: error will be set if an MContentHandler function has left,
       
   149 	// status notifies us of an internal from Expat
       
   150 	TRAP(error, status=XML_ParseBuffer(iParser, iInputBuffer.Length(), done));
       
   151 
       
   152 	if(error!=KErrNone)
       
   153 		{
       
   154 		// If a MContentHandler function left it is possible that some allocated memory may be
       
   155 		// leaked.  We don't take that chance and de-allocate the parser and all its memory.
       
   156 		iParser = 0;
       
   157 		iAllocator.ResetL();
       
   158 
       
   159 		ClearElementStack();
       
   160 		
       
   161 		// ResetL must be called to re-activate it.
       
   162 		ResetL();
       
   163 		
       
   164 		User::Leave(error);
       
   165 		}
       
   166 		
       
   167 	if(status==XML_STATUS_ERROR)
       
   168 		{
       
   169 		error = (TInt)XML_GetErrorCode(iParser);
       
   170 
       
   171 		if(error == (TInt)XML_ERROR_NO_MEMORY)
       
   172 			error = KErrNoMemory;
       
   173 		else
       
   174 			error += (EXmlSyntax-XML_ERROR_SYNTAX);  // Convert to our external error range
       
   175 
       
   176 		ClearElementStack();
       
   177 
       
   178 		// We don't want to regenerate the same callback. So check
       
   179 		// that the conditions are different.
       
   180 		// I.e. if the last parse resulted in a fatal error then
       
   181 		// subsequent parses will invoke the errorProcessor with the 
       
   182 		// same error and status returned. Nothing more will be parsed.
       
   183 		if (iPrevStatus != XML_STATUS_ERROR || iPrevError != error)
       
   184 			{
       
   185 			iContentHandler->OnError(error);
       
   186 			}
       
   187 		}
       
   188 	else if(done)
       
   189 		{
       
   190 		iContentHandler->OnEndDocumentL(KErrNone);
       
   191 		}
       
   192 
       
   193 	iPrevError = error;
       
   194 	iPrevStatus = status;
       
   195 	}
       
   196 
       
   197 const TInt KOptionalFeatures  = EConvertTagsToLowerCase | EReportNamespaceMapping;
       
   198 const TInt KMandatoryFeatures = EReportNamespaces | EReportNamespacePrefixes;
       
   199 
       
   200 TInt CExpat::EnableFeature(TInt aParseMode)
       
   201 	{
       
   202 	if(aParseMode & ~(KOptionalFeatures | KMandatoryFeatures))
       
   203 		return KErrNotSupported;
       
   204 
       
   205 	iParseMode |= aParseMode | KMandatoryFeatures;
       
   206 
       
   207 	return KErrNone;
       
   208 	}
       
   209 
       
   210 TInt CExpat::DisableFeature(TInt aParseMode)
       
   211 	{
       
   212 	if(aParseMode & KMandatoryFeatures)
       
   213 		return KErrNotSupported;
       
   214 
       
   215 	iParseMode &= ~aParseMode;
       
   216 
       
   217 	return KErrNone;
       
   218 	}
       
   219 
       
   220 TBool CExpat::IsFeatureEnabled(TInt aParseMode) const
       
   221 	{
       
   222 	return iParseMode & aParseMode;
       
   223 	}
       
   224 
       
   225 
       
   226 void CExpat::SetContentSink(class MContentHandler &aContentSink)
       
   227 	{
       
   228 	iContentHandler = &aContentSink;
       
   229 	}
       
   230 
       
   231 /*
       
   232 CreateRStringL converts the UTF-16 descriptor to UTF-8 and stores it in the stringpool.
       
   233 */
       
   234 void CExpat::CreateRStringL(const TDesC& aInput, RString& aString, TBool aLowerCase)
       
   235 	{
       
   236 	TPtr8 conversionOutput(0,0);
       
   237 	//Uses the more efficient TPtr overload of ConvertFromUnicode.
       
   238 	TInt error = iCharSetConverter.ConvertFromUnicodeL(aInput, KCharacterSetIdentifierUtf8, conversionOutput);	
       
   239 	User::LeaveIfError(error>0 ? KErrCorrupt : error);
       
   240 
       
   241 	if(aLowerCase)
       
   242 		conversionOutput.LowerCase();
       
   243 
       
   244 	aString = iStringPool.OpenStringL(conversionOutput);
       
   245 	}
       
   246 
       
   247 /*
       
   248 ScanNameL takes a null-terminated UTF-16 string of the form "uri!prefix!localpart" (although prefix, or uri and prefix,
       
   249 may not be there.  The separated parts will be converted to UTF-8 and stored in the stringpool.
       
   250 
       
   251 The prefix and local part will be converted to lowercase if EConvertTagsToLowerCase is one of the
       
   252 current parse modes.
       
   253 */
       
   254 void CExpat::ScanNameL(const XML_Char* aName16, RString& aUriString, RString& aLocalPartString, RString& aPrefixString)
       
   255 	{
       
   256 	const TUint16* uri = 0;
       
   257 	const TUint16* prefix = 0;
       
   258 	const TUint16* localPart;
       
   259 	const TUint16* p;
       
   260 
       
   261 	p = localPart = (TUint16*)aName16;
       
   262 
       
   263 	while(*p)
       
   264 		if(*p++ == KNamespaceSeparator)
       
   265 			{
       
   266 			uri = (TUint16*)aName16;
       
   267 			localPart = p;
       
   268 			break;
       
   269 			}
       
   270 
       
   271 	while(*p)
       
   272 		if(*p++ == KNamespaceSeparator)
       
   273 			{
       
   274 			prefix = p;
       
   275 			break;
       
   276 			}
       
   277 
       
   278 	while(*p)
       
   279 		p++;
       
   280 
       
   281 	TBool lowerCase = iParseMode & EConvertTagsToLowerCase;
       
   282 	XML_Char nullString[] = "";
       
   283 
       
   284 	if(uri)
       
   285 		CreateRStringL(TPtrC16(uri, localPart-uri-1), aUriString, EFalse);
       
   286 	else
       
   287 		aUriString = iStringPool.OpenStringL(TPtrC8((unsigned char*)nullString, 0));
       
   288 	CleanupClosePushL(aUriString);
       
   289 
       
   290 
       
   291 	if(prefix)
       
   292 		CreateRStringL(TPtrC16(prefix, p-prefix), aPrefixString , lowerCase);
       
   293 	else
       
   294 		aPrefixString = iStringPool.OpenStringL(TPtrC8((unsigned char*)nullString, 0));
       
   295 	CleanupClosePushL(aPrefixString);
       
   296 
       
   297 	CreateRStringL(TPtrC16(localPart, (prefix ? prefix-1 : p)-localPart), aLocalPartString, lowerCase);
       
   298 
       
   299 	CleanupStack::Pop(2);
       
   300 	} 
       
   301 
       
   302 void CExpat::StartElementHandlerL(void* aUserData, const XML_Char* aName, const XML_Char** aAtts)
       
   303 	{
       
   304 	((CExpat*)aUserData)->HandleStartElementL(aName, aAtts);
       
   305 	}
       
   306 
       
   307 void CExpat::HandleStartElementL(const XML_Char* aName, const XML_Char** aAtts)
       
   308 	{
       
   309 	RString uriString, nameString, prefixString;
       
   310 	ScanNameL(aName, uriString, nameString, prefixString);
       
   311 
       
   312 	RTagInfo tagInfo;
       
   313 	tagInfo.Open(uriString, prefixString, nameString);
       
   314 	CleanupClosePushL(tagInfo);
       
   315 
       
   316 	// Only create a copy of nameString if the append succeeds
       
   317 	User::LeaveIfError(iElementStack.Append(nameString));
       
   318 	nameString.Copy(); // i.e. iElementStack now has a copy so flag this to the stringpool
       
   319 
       
   320 	// Count the number of attributes in aAtts
       
   321 	//
       
   322 	// The layout of aAtts is an array of name, value, name, value, name, ...
       
   323 	// ... hence each attribute has two strings giving rise to the "att += 2;"
       
   324 	const XML_Char** att = aAtts;
       
   325 	while (*att)
       
   326 		att += 2;
       
   327 	TInt nAttributes = (att-aAtts)/2;
       
   328 
       
   329 	RAttributeArray attributes;
       
   330 	CleanupStack::PushL(TCleanupItem(AttributeArrayDelete, &attributes));
       
   331 
       
   332 	att = aAtts;
       
   333 	for(TInt i=0; i<nAttributes; i++)
       
   334 		{
       
   335 		RString attUriString, attNameString, attPrefixString;
       
   336 		ScanNameL(*att, attUriString, attNameString, attPrefixString);
       
   337 		CleanupClosePushL(attUriString);
       
   338 		CleanupClosePushL(attNameString);
       
   339 		CleanupClosePushL(attPrefixString);
       
   340 		att++;
       
   341 
       
   342 		
       
   343 		RString attValueString;
       
   344 		CreateRStringL(TPtrC((TUint16*)*att, StringLen((TUint16*)*att)), attValueString, EFalse);
       
   345 		att++;
       
   346 
       
   347 		CleanupStack::Pop(3);  // RAttribute will own the RStrings
       
   348 
       
   349 		RAttribute attribute;
       
   350 		attribute.Open(attUriString, attPrefixString, attNameString, attValueString);
       
   351 
       
   352 		CleanupClosePushL(attribute);
       
   353 		User::LeaveIfError(attributes.Append(attribute));
       
   354 		CleanupStack::Pop();
       
   355 		}
       
   356 
       
   357 	iContentHandler->OnStartElementL(tagInfo, attributes, KErrNone);
       
   358 
       
   359 	CleanupStack::PopAndDestroy(2);  // Finished with RTagInfo and RAttributeArray
       
   360 	}
       
   361 
       
   362 void CExpat::EndElementHandlerL(void* aUserData, const XML_Char* aName)
       
   363 	{
       
   364 	((CExpat*)aUserData)->HandleEndElementL(aName);
       
   365 	}
       
   366 
       
   367 void CExpat::HandleEndElementL(const XML_Char* aName)
       
   368 	{
       
   369 	RString uriString, nameString, prefixString;
       
   370 	ScanNameL(aName, uriString, nameString, prefixString);
       
   371 
       
   372 	RTagInfo tagInfo;
       
   373 	tagInfo.Open(uriString, prefixString, nameString);
       
   374 	CleanupClosePushL(tagInfo);
       
   375 
       
   376 	TInt i = iElementStack.Count() - 1;
       
   377 
       
   378 	// Expat will raise an error if the wrong element is closed.  We only get an error here
       
   379 	// if somehow our element stack is wrong.
       
   380 	if(iElementStack[i]!=nameString)
       
   381 		User::Leave(KErrCorrupt);
       
   382 	
       
   383 	iElementStack[i].Close();
       
   384 	iElementStack.Remove(i);
       
   385 
       
   386 	iContentHandler->OnEndElementL(tagInfo, KErrNone);
       
   387 
       
   388 	CleanupStack::PopAndDestroy();  // Finished with RTagInfo
       
   389 	}
       
   390 
       
   391 void CExpat::CharacterDataHandlerL(void* aUserData, const XML_Char* aString, int aLen)
       
   392 	{
       
   393 	((CExpat*)aUserData)->HandleCharacterDataL(aString, aLen);
       
   394 	}
       
   395 
       
   396 void CExpat::HandleCharacterDataL(const XML_Char* aString, int aLen)
       
   397 	{
       
   398 	TPtr8 conversionOutput(0,0);
       
   399 	//Uses the more efficient TPtr overload of ConvertFromUnicode
       
   400 	TInt error = iCharSetConverter.ConvertFromUnicodeL(TPtrC16((TUint16*)aString, aLen), KCharacterSetIdentifierUtf8, conversionOutput);
       
   401 	User::LeaveIfError(error>0 ? KErrCorrupt : error);
       
   402 	iContentHandler->OnContentL(conversionOutput, KErrNone);
       
   403 	}
       
   404 
       
   405 void CExpat::ProcessingInstructionHandlerL(void* aUserData, const XML_Char* aTarget, const XML_Char* aData)
       
   406 	{
       
   407 	((CExpat*)aUserData)->HandleProcessingInstructionL(aTarget, aData);
       
   408 	}
       
   409 
       
   410 void CExpat::HandleProcessingInstructionL(const XML_Char* aTarget, const XML_Char* aData)
       
   411 	{
       
   412 	TPtr8 utf8target(0,0);
       
   413 	//Uses the more efficient TPtr overload of the ConvertFromUnicodeL function
       
   414 	TInt error = iCharSetConverter.ConvertFromUnicodeL(TPtrC16((TUint16*)aTarget, StringLen((TUint16*)aTarget)), KCharacterSetIdentifierUtf8, utf8target);
       
   415 	User::LeaveIfError(error>0 ? KErrCorrupt : error);
       
   416 
       
   417 	HBufC8 *utf8data;
       
   418 	//Uses the HBufC overload of ConvertFromUnicodeL as the data in the TPtr overload is still needed. 
       
   419 	error = iCharSetConverter.ConvertFromUnicodeL(TPtrC16((TUint16*)aData, StringLen((TUint16*)aData)), KCharacterSetIdentifierUtf8, utf8data);
       
   420 	CleanupStack::PushL(utf8data);
       
   421 	User::LeaveIfError(error>0 ? KErrCorrupt : error);
       
   422 
       
   423 	iContentHandler->OnProcessingInstructionL(utf8target, utf8data->Des(), KErrNone);
       
   424 
       
   425 	CleanupStack::PopAndDestroy(utf8data);
       
   426 	}
       
   427 
       
   428 void CExpat::XmlDeclHandlerL(void* aUserData, const XML_Char* aVersion, const XML_Char* aEncoding, int aStandalone)
       
   429 	{
       
   430 	((CExpat*)aUserData)->HandleXmlDeclL(aVersion, aEncoding, aStandalone);
       
   431 	}
       
   432 
       
   433 void CExpat::HandleXmlDeclL(const XML_Char*, const XML_Char* aEncoding16, int)
       
   434 	{
       
   435 	//
       
   436 	// Encoding
       
   437 	//
       
   438 	RString encodingString;
       
   439 	
       
   440 	if (aEncoding16)
       
   441 		{
       
   442 		TInt len = StringLen((TUint16*)aEncoding16);
       
   443 		TPtr8 encoding8 = HBufC8::NewLC(len)->Des();
       
   444 		encoding8.Copy(TPtrC16((TUint16*)aEncoding16, len));
       
   445 		encodingString = iStringPool.OpenStringL(encoding8);
       
   446 		CleanupStack::PopAndDestroy();
       
   447 		}
       
   448 	else
       
   449 		{
       
   450 		encodingString = iStringPool.OpenStringL(KNullDesC8());
       
   451 		}
       
   452 		
       
   453 	CleanupClosePushL(encodingString);
       
   454 
       
   455 	RDocumentParameters params;
       
   456 	params.Open(encodingString);
       
   457 	CleanupStack::Pop(); // encodingString
       
   458 	CleanupClosePushL(params);
       
   459 
       
   460 	iContentHandler->OnStartDocumentL(params, KErrNone);
       
   461 
       
   462 	CleanupStack::PopAndDestroy();  // Finished with params
       
   463 	}
       
   464 
       
   465 void CExpat::StartNamespaceDeclHandlerL(void* aUserData, const XML_Char* aPrefix, const XML_Char* aUri)
       
   466 	{
       
   467 	((CExpat*)aUserData)->HandleStartNamespaceDeclL(aPrefix, aUri);
       
   468 	}
       
   469 
       
   470 void CExpat::HandleStartNamespaceDeclL(const XML_Char* aPrefix, const XML_Char* aUri)
       
   471 	{
       
   472 	if(iParseMode & EReportNamespaceMapping)
       
   473 		{
       
   474 		RString prefixString;
       
   475 		RString uriString;
       
   476 		unsigned char nullString[] = "";
       
   477 
       
   478 		if(aPrefix)
       
   479 			CreateRStringL(TPtrC((TUint16*)aPrefix, StringLen((TUint16*)aPrefix)), prefixString, EFalse);
       
   480 		else
       
   481 			{
       
   482 			prefixString = iStringPool.OpenStringL(TPtrC8(nullString, 0));
       
   483 			}
       
   484 		CleanupClosePushL(prefixString);
       
   485 
       
   486 
       
   487 		if(aUri)
       
   488 			CreateRStringL(TPtrC((TUint16*)aUri, StringLen((TUint16*)aUri)), uriString, EFalse);
       
   489 		else
       
   490 			{
       
   491 			uriString = iStringPool.OpenStringL(TPtrC8(nullString, 0));
       
   492 			}
       
   493 		CleanupClosePushL(uriString);
       
   494 
       
   495 		iContentHandler->OnStartPrefixMappingL(prefixString, uriString, KErrNone);
       
   496 
       
   497 		CleanupStack::PopAndDestroy(2);
       
   498 		}
       
   499 	}
       
   500 
       
   501 void CExpat::EndNamespaceDeclHandlerL(void* aUserData, const XML_Char* aPrefix)
       
   502 	{
       
   503 	((CExpat*)aUserData)->HandleEndNamespaceDeclL(aPrefix);
       
   504 	}
       
   505 
       
   506 void CExpat::HandleEndNamespaceDeclL(const XML_Char* aPrefix)
       
   507 	{
       
   508 	if(iParseMode & EReportNamespaceMapping)
       
   509 		{
       
   510 		RString prefixString;
       
   511 
       
   512 		if(aPrefix)
       
   513 			CreateRStringL(TPtrC((TUint16*)aPrefix, StringLen((TUint16*)aPrefix)), prefixString, EFalse);
       
   514 		else
       
   515 			{
       
   516 			unsigned char nullString[] = "";
       
   517 			prefixString = iStringPool.OpenStringL(TPtrC8(nullString, 0));
       
   518 			}
       
   519 
       
   520 		CleanupClosePushL(prefixString);
       
   521 		iContentHandler->OnEndPrefixMappingL(prefixString, KErrNone);
       
   522 		CleanupStack::PopAndDestroy();
       
   523 		}
       
   524 	}
       
   525 
       
   526 void CExpat::SkippedEntityHandlerL(void* aUserData, const XML_Char* aName, int aIsParamEntity)
       
   527 	{
       
   528 	((CExpat*)aUserData)->HandleSkippedEntityL(aName, aIsParamEntity);
       
   529 	}
       
   530 
       
   531 void CExpat::HandleSkippedEntityL(const XML_Char* aName, int)
       
   532 	{
       
   533 	RString nameString;
       
   534 	CreateRStringL(TPtrC((TUint16*)aName, StringLen((TUint16*)aName)), nameString, EFalse);
       
   535 
       
   536 	CleanupClosePushL(nameString);
       
   537 	iContentHandler->OnSkippedEntityL(nameString, KErrNone);
       
   538 	CleanupStack::PopAndDestroy();
       
   539 	}
       
   540 
       
   541 int CExpat::ExternalEntityRefHandlerL(void* aUserData, const XML_Char* aName)
       
   542 	{
       
   543 	((CExpat*)aUserData)->HandleSkippedEntityL(aName, 0);
       
   544 	return 1;
       
   545 	}
       
   546 
       
   547 void CExpat::ClearElementStack()
       
   548 	{
       
   549 	for(TInt i=iElementStack.Count()-1; i>=0; i--)
       
   550 		iElementStack[i].Close();
       
   551 
       
   552 	iElementStack.Reset();
       
   553 	}
       
   554 
       
   555 LOCAL_C void AttributeArrayDelete(TAny *aPtr)
       
   556 	{
       
   557 	RAttributeArray& attributes = *(RAttributeArray*)aPtr;
       
   558 
       
   559 	TInt nAttributes = attributes.Count();
       
   560 
       
   561 	for(TInt i=0; i<nAttributes; i++)
       
   562 		attributes[i].Close();
       
   563 
       
   564 	attributes.Close();
       
   565 	}
       
   566 
       
   567 RHeap* CExpat::GetInternalHeap() const
       
   568 	{
       
   569 	return iAllocator.GetHeap();
       
   570 	}
       
   571 
       
   572 
       
   573 //
       
   574 // CExpat::TExpatAlloc
       
   575 //
       
   576 #ifndef _DEBUG
       
   577 void CExpat::TExpatAlloc::ConstructL(TInt aHeapSize, TInt)
       
   578 	{
       
   579 #else
       
   580 void CExpat::TExpatAlloc::ConstructL(TInt aHeapSize, TInt aDebugFailCount)
       
   581 	{
       
   582 	// The first failure is a simulated chunk/heap creation failure
       
   583 	if(aDebugFailCount==1)
       
   584 		User::Leave(KErrNoMemory);
       
   585 #endif
       
   586 
       
   587 	iHeapSize = aHeapSize;
       
   588 	iHeap = (RHeap*)User::LeaveIfNull(UserHeap::ChunkHeap(0, aHeapSize, aHeapSize));
       
   589 
       
   590 #ifdef _DEBUG
       
   591 	if(aDebugFailCount)
       
   592 		iHeap->__DbgSetAllocFail(RHeap::EFailNext, aDebugFailCount-1);
       
   593 #endif
       
   594 	}
       
   595 
       
   596 CExpat::TExpatAlloc::~TExpatAlloc()
       
   597 	{
       
   598 	if(iHeap)
       
   599 		{
       
   600 		iHeap->Close();
       
   601 		iHeap = 0;
       
   602 		}
       
   603 	}
       
   604 
       
   605 void CExpat::TExpatAlloc::ResetL()
       
   606 	{
       
   607 	__ASSERT_DEBUG(iHeap, User::Invariant());
       
   608 	
       
   609 	if(iHeap)
       
   610 		iHeap->Close();
       
   611 	iHeap = UserHeap::ChunkHeap(0, iHeapSize, iHeapSize);
       
   612 	User::LeaveIfNull(iHeap);
       
   613 	}
       
   614 
       
   615 void CExpat::TExpatAlloc::FillAllocStruct(XML_Memory_Handling_Suite& aMem) const
       
   616 	{
       
   617 	aMem.malloc_fcn = CExpat::TExpatAlloc::Alloc;
       
   618 	aMem.realloc_fcn = CExpat::TExpatAlloc::ReAlloc;
       
   619 	aMem.free_fcn = CExpat::TExpatAlloc::Free;
       
   620 	aMem.allocData = (void*)this;
       
   621 	}
       
   622 
       
   623 void* CExpat::TExpatAlloc::Alloc(void* aUserData, size_t aSize)
       
   624 	{
       
   625 	RHeap* heap = ((TExpatAlloc*)aUserData)->iHeap;
       
   626 	return heap ? heap->Alloc(aSize) : 0;
       
   627 	}
       
   628 
       
   629 void* CExpat::TExpatAlloc::ReAlloc(void* aUserData, void* aPtr, size_t aSize)
       
   630 	{
       
   631 	RHeap* heap = ((TExpatAlloc*)aUserData)->iHeap;
       
   632 
       
   633 	// Used during development to ensure good heap.  Left in for future reference
       
   634 	__ASSERT_DEBUG(heap, User::Invariant());
       
   635 
       
   636 	return heap ? heap->ReAlloc(aPtr, aSize) : 0;
       
   637 	}
       
   638 
       
   639 void CExpat::TExpatAlloc::Free(void* aUserData, void *aPtr)
       
   640 	{
       
   641 	RHeap* heap = ((TExpatAlloc*)aUserData)->iHeap;
       
   642 
       
   643 	// Used during development to ensure good heap.  Left in for future reference
       
   644 	__ASSERT_DEBUG(heap, User::Invariant());
       
   645 
       
   646 	if(heap)
       
   647 		heap->Free(aPtr);
       
   648 	}
       
   649 
       
   650 RHeap* CExpat::TExpatAlloc::GetHeap() const
       
   651 	{
       
   652 	return iHeap;
       
   653 	}