|         |      1 // Copyright (c) 2001-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 // @file | 
|         |     15 // This file contains the definition of the generic CMDXMLParser class | 
|         |     16 // which is responsible for creating a DOM structure | 
|         |     17 // from a given XML file. | 
|         |     18 //  | 
|         |     19 // | 
|         |     20  | 
|         |     21 #include <f32file.h> | 
|         |     22 #include <utf.h> | 
|         |     23 #include <bautils.h> | 
|         |     24  | 
|         |     25 #include <gmxmlconstants.h> | 
|         |     26 #include <gmxmlcomposer.h> | 
|         |     27 #include <gmxmlentityconverter.h> | 
|         |     28 #include <gmxmlnode.h> | 
|         |     29 #include <gmxmldocument.h> | 
|         |     30 #include <gmxmlelement.h> | 
|         |     31 #include <gmxmlparser.h> | 
|         |     32 #include <gmxmlprocessinginstruction.h> | 
|         |     33 #include <gmxmlcomment.h> | 
|         |     34 #include <gmxmlcdatasection.h> | 
|         |     35 #include <gmxmltext.h> | 
|         |     36  | 
|         |     37 #include "GMXMLFileDataSource.h" | 
|         |     38 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS  | 
|         |     39 #include "gmxmldummydtd.h" | 
|         |     40 #endif | 
|         |     41  | 
|         |     42 const TInt KGMXMLDefaultTextBufferSize = 1024; | 
|         |     43 const TInt KUTF8EdgeBufferLen = 6; | 
|         |     44  | 
|         |     45 // | 
|         |     46 // Global functions					// | 
|         |     47 // | 
|         |     48  | 
|         |     49  | 
|         |     50 //================================================================================== | 
|         |     51  | 
|         |     52 // | 
|         |     53 //CMDXParser						// | 
|         |     54 // | 
|         |     55 //================================================================================== | 
|         |     56  | 
|         |     57 void CMDXMLParser::Panic(TPanicCode aReason) const | 
|         |     58 	{ | 
|         |     59 	_LIT(KClassName, "CMDXMLParser"); | 
|         |     60 	User::Panic(KClassName, aReason); | 
|         |     61 	} | 
|         |     62  | 
|         |     63 EXPORT_C CMDXMLParser* CMDXMLParser::NewL(MMDXMLParserObserver* aParserObserver) | 
|         |     64 // | 
|         |     65 // Two phase static factory function constructor | 
|         |     66 // @return Created CMDXMLParser | 
|         |     67 // @leave can Leave due to OOM | 
|         |     68 // | 
|         |     69 	{ | 
|         |     70 	CMDXMLParser* self = NewLC(aParserObserver); | 
|         |     71 	CleanupStack::Pop(); | 
|         |     72 	return self; | 
|         |     73 	} | 
|         |     74  | 
|         |     75 EXPORT_C CMDXMLParser* CMDXMLParser::NewL(MMDXMLParserObserver* aParserObserver, MXMLDtd* aDtdRepresentation) | 
|         |     76 // | 
|         |     77 // Two phase static factory function constructor | 
|         |     78 // @return Created CMDXMLParser | 
|         |     79 // @param aDtdRepresentation specid DTD represention class to be used for validation | 
|         |     80 // @leave can Leave due to OOM | 
|         |     81 // | 
|         |     82 	{ | 
|         |     83 	CMDXMLParser* self = NewLC(aParserObserver, aDtdRepresentation); | 
|         |     84 	CleanupStack::Pop(); | 
|         |     85 	return self; | 
|         |     86 	} | 
|         |     87  | 
|         |     88  | 
|         |     89 //================================================================================== | 
|         |     90  | 
|         |     91 EXPORT_C CMDXMLParser* CMDXMLParser::NewLC(MMDXMLParserObserver* aParserObserver) | 
|         |     92 // | 
|         |     93 // Two phase static factory function constructor | 
|         |     94 // @return Created CMDXMLParser | 
|         |     95 // @leave can Leave due to OOM | 
|         |     96 // | 
|         |     97 	{ | 
|         |     98 	CMDXMLParser* self = new (ELeave) CMDXMLParser(aParserObserver); | 
|         |     99 	CleanupStack::PushL(self); | 
|         |    100 	// This overload of NewLC doesn't take a MXMLDtd*, but we need to provide one to | 
|         |    101 	// ConstructL where ownership is taken if we do have one.  Just pass NULL. | 
|         |    102 	self->ConstructL(NULL); | 
|         |    103 	return self; | 
|         |    104 	} | 
|         |    105  | 
|         |    106 EXPORT_C CMDXMLParser* CMDXMLParser::NewLC(MMDXMLParserObserver* aParserObserver, MXMLDtd* aDtdRepresentation) | 
|         |    107 // | 
|         |    108 // Two phase static factory function constructor | 
|         |    109 // @return Created CMDXMLParser | 
|         |    110 // @param aDtdRepresentation specid DTD represention class to be used for validation | 
|         |    111 // @leave can Leave due to OOM | 
|         |    112 // | 
|         |    113 	{ | 
|         |    114 	CMDXMLParser* self = new (ELeave) CMDXMLParser(aParserObserver); | 
|         |    115 	CleanupStack::PushL(self); | 
|         |    116 	self->ConstructL(aDtdRepresentation); | 
|         |    117 	return self; | 
|         |    118 	} | 
|         |    119  | 
|         |    120  | 
|         |    121 //================================================================================== | 
|         |    122  | 
|         |    123 void CMDXMLParser::ConstructL(MXMLDtd* aDtdRepresentation) | 
|         |    124 // | 
|         |    125 // Second stage constructor | 
|         |    126 // @param aDtdRepresentation The DTD to be used for validation | 
|         |    127 // @leave can Leave due to OOM | 
|         |    128 // | 
|         |    129 	{ | 
|         |    130 	CMDXMLEntityConverter* entityConverter = new(ELeave) CMDXMLEntityConverter(); | 
|         |    131 	SetEntityConverter(entityConverter); | 
|         |    132  | 
|         |    133 	// This doesn't leave, but if CMDXMLParser::NewLC() Leaves after taking ownership | 
|         |    134 	// of this we'll get a double deletion as the caller will have pushed  | 
|         |    135 	// aDtdRepresentation onto the CleanupStack.  As such we can only take ownership | 
|         |    136 	// once we are sure we aren't going to leave. | 
|         |    137 	iDtdRepresentation = aDtdRepresentation; | 
|         |    138 	} | 
|         |    139  | 
|         |    140 CMDXMLParser::CMDXMLParser(MMDXMLParserObserver* aParserObserver) | 
|         |    141 	: CActive(EPriorityNormal) | 
|         |    142 // | 
|         |    143 // Constructor | 
|         |    144 // | 
|         |    145 	{ | 
|         |    146 	iParserObserver = aParserObserver; | 
|         |    147 	iStoreInvalid = ETrue; | 
|         |    148 	CActiveScheduler::Add(this); | 
|         |    149 	} | 
|         |    150  | 
|         |    151 //================================================================================== | 
|         |    152  | 
|         |    153 EXPORT_C CMDXMLParser::~CMDXMLParser() | 
|         |    154 	{ | 
|         |    155 	Cancel(); | 
|         |    156 	delete iBomBuffer; | 
|         |    157 	if( iFileSource == NULL ) | 
|         |    158 		{ | 
|         |    159 		// iFileSource has not been allocated yet, so the file path or file | 
|         |    160 		// handle are still owned | 
|         |    161 		if( iFileToParse!=NULL ) | 
|         |    162 			delete iFileToParse; | 
|         |    163 		else | 
|         |    164 			iFileHandleToParse.Close(); | 
|         |    165 		} | 
|         |    166 	else | 
|         |    167 		{ | 
|         |    168 		delete iFileSource; | 
|         |    169 		} | 
|         |    170 	delete iUTF8EdgeBuffer; | 
|         |    171 	delete iXMLDoc; | 
|         |    172 	delete iEntityConverter; | 
|         |    173 	delete iElementTag; | 
|         |    174 	delete iDtdRepresentation; | 
|         |    175 	delete iText; | 
|         |    176 	} | 
|         |    177  | 
|         |    178 //================================================================================== | 
|         |    179 //Defect fix for INC036136- Enable the use of custom entity converters in GMXML | 
|         |    180 EXPORT_C void CMDXMLParser::SetEntityConverter(CMDXMLEntityConverter* aEntityConverter) | 
|         |    181 /* | 
|         |    182 	 * Sets the entity converter to be used | 
|         |    183 	 * and  take ownership of the passed entity converter | 
|         |    184 	 * @param aEntityConverter The entity converter to be used | 
|         |    185 	 */ | 
|         |    186 	{ | 
|         |    187 	delete iEntityConverter; | 
|         |    188 	iEntityConverter = aEntityConverter; | 
|         |    189 	} | 
|         |    190 //End Defect fix for INC036136 | 
|         |    191 //================================================================================== | 
|         |    192  | 
|         |    193 EXPORT_C void CMDXMLParser::SetStoreInvalid(TBool aStoreInvalid) | 
|         |    194 	{ | 
|         |    195 	iStoreInvalid = aStoreInvalid; | 
|         |    196 	} | 
|         |    197 	 | 
|         |    198 //================================================================================== | 
|         |    199 // Defect fix for INC105134 - GmXML consumes whitespace characters  | 
|         |    200 //==================================================================================	 | 
|         |    201 EXPORT_C void CMDXMLParser::SetWhiteSpaceHandlingMode(TBool aPreserve) | 
|         |    202     { | 
|         |    203     iPreserve = aPreserve; | 
|         |    204     } | 
|         |    205  | 
|         |    206 // End Defect fix for INC105134 | 
|         |    207 //================================================================================== | 
|         |    208 EXPORT_C CMDXMLDocument* CMDXMLParser::DetachXMLDoc() | 
|         |    209 // | 
|         |    210 // @return CMDXMLDocument* to the created DOM, should be called after the | 
|         |    211 // conclusion of the parser process.  Note that internal variable pointing to | 
|         |    212 // the document is set to NULL so this function can only be called once per file | 
|         |    213 // parse.  Client application must take ownership of document for cleanup purposes. | 
|         |    214 // | 
|         |    215 	{ | 
|         |    216 	CMDXMLDocument* returnDoc = iXMLDoc; | 
|         |    217 	iXMLDoc = NULL; | 
|         |    218 	return returnDoc; | 
|         |    219 	} | 
|         |    220  | 
|         |    221 //================================================================================== | 
|         |    222  | 
|         |    223 CMDXMLEntityConverter* CMDXMLParser::EntityConverter() | 
|         |    224 // | 
|         |    225 // @return the CMDXMLEntityConverter for use in converting built in entity | 
|         |    226 // and character entities back to their original format | 
|         |    227 // | 
|         |    228 	{ | 
|         |    229 	return iEntityConverter; | 
|         |    230 	} | 
|         |    231  | 
|         |    232 //================================================================================== | 
|         |    233  | 
|         |    234 EXPORT_C TInt CMDXMLParser::ParseFile(RFs aRFs, const TDesC& aFileToParse) | 
|         |    235 // | 
|         |    236 // ParseFile opens a file ready for parsing | 
|         |    237 // @param aRFs a resource file session used for file I/O | 
|         |    238 // @param aFileToParse the file name to parse | 
|         |    239 // @return KErrNone if all OK or file read error code | 
|         |    240 // | 
|         |    241 	{ | 
|         |    242 	//Find out whether the file exists. If not dont start the active object | 
|         |    243 	if(!BaflUtils::FileExists(aRFs,aFileToParse)) | 
|         |    244 		{ | 
|         |    245 		return KErrNotFound; | 
|         |    246 		} | 
|         |    247 	else | 
|         |    248 		{	 | 
|         |    249 		//Check whether the file is locked by any other process				 | 
|         |    250 		RFile tempFile; | 
|         |    251 		TInt err=tempFile.Open(aRFs, aFileToParse, EFileRead | EFileShareReadersOnly);		 | 
|         |    252 		if(err!=KErrNone) | 
|         |    253 			{ | 
|         |    254 			return err;					 | 
|         |    255 			} | 
|         |    256 		tempFile.Close();	 | 
|         |    257 		}	 | 
|         |    258 	Cancel(); | 
|         |    259 	iSuspiciousCharacter = KErrNotFound; | 
|         |    260 	iError = KErrNone; | 
|         |    261 	iSeverity = EXMLNone; | 
|         |    262 	iDocTypeSet = EFalse; | 
|         |    263 	iVersionSet = EFalse; | 
|         |    264  | 
|         |    265 	/* We need to open our file in a leave-safe place as it involves | 
|         |    266 	   a heap alloc, and so we'll set up the AO to do that when it runs next. | 
|         |    267 	*/ | 
|         |    268 	delete iFileToParse; | 
|         |    269 	iFileToParse = aFileToParse.Alloc(); | 
|         |    270 	if(iFileToParse == NULL) | 
|         |    271 		{ | 
|         |    272 		return KErrNoMemory; | 
|         |    273 		} | 
|         |    274  | 
|         |    275 	iRFs = aRFs; | 
|         |    276 	iState = KInitFromFile; | 
|         |    277  | 
|         |    278 	SetActive(); | 
|         |    279 	TRequestStatus* s=&iStatus; | 
|         |    280 	User::RequestComplete(s, KErrNone); | 
|         |    281  | 
|         |    282 	return KErrNone; | 
|         |    283 	} | 
|         |    284 	 | 
|         |    285 /**  | 
|         |    286 Parses a specified XML file into a DOM object tree. | 
|         |    287  | 
|         |    288 Parses a specified XML file into a DOM object tree using an open file handle. The  | 
|         |    289 parser takes ownership of the open file handle and will close handle when completed. | 
|         |    290  | 
|         |    291 @param aFileHandleToParse An open file handle for the file to parse. Ownership of the | 
|         |    292 	   file handle is passed. | 
|         |    293 @return KErrNone if successful. | 
|         |    294 */ | 
|         |    295 EXPORT_C TInt CMDXMLParser::ParseFile(RFile& aFileHandleToParse) | 
|         |    296 	{	 | 
|         |    297 	iFileHandleToParse = aFileHandleToParse; | 
|         |    298  | 
|         |    299 	Cancel(); | 
|         |    300 	iSuspiciousCharacter = KErrNotFound; | 
|         |    301 	iError = KErrNone; | 
|         |    302 	iSeverity = EXMLNone; | 
|         |    303 	iDocTypeSet = EFalse; | 
|         |    304 	iVersionSet = EFalse; | 
|         |    305  | 
|         |    306 	iState = KInitFromFile; | 
|         |    307  | 
|         |    308 	iStatus = KRequestPending; | 
|         |    309 	SetActive(); | 
|         |    310 	TRequestStatus* s=&iStatus; | 
|         |    311 	User::RequestComplete(s, KErrNone); | 
|         |    312  | 
|         |    313 	return KErrNone; | 
|         |    314 	} | 
|         |    315 //================================================================================== | 
|         |    316  | 
|         |    317 EXPORT_C void CMDXMLParser::ParseSourceL(MMDXMLParserDataProvider *aSource) | 
|         |    318 	{ | 
|         |    319 	iSuspiciousCharacter = KErrNotFound; | 
|         |    320 	iError = KErrNone; | 
|         |    321 	iSeverity = EXMLNone; | 
|         |    322 	iDocTypeSet = EFalse; | 
|         |    323 	iVersionSet = EFalse; | 
|         |    324  | 
|         |    325 	iDataSource = aSource; | 
|         |    326 	PrepareForReuseL(); | 
|         |    327 	GetMoreData(); | 
|         |    328 	} | 
|         |    329  | 
|         |    330 //================================================================================== | 
|         |    331  | 
|         |    332 void CMDXMLParser::PrepareForReuseL() | 
|         |    333 	{ | 
|         |    334 	Cancel(); | 
|         |    335  | 
|         |    336 	iError = KErrNone; | 
|         |    337 	iSeverity = EXMLNone; | 
|         |    338 	iDocTypeSet = EFalse; | 
|         |    339 	iVersionSet = EFalse; | 
|         |    340 	iBytesPerChar = 0; | 
|         |    341 	iNextChar = 0; | 
|         |    342 	iInputBytesRemaining = 0; | 
|         |    343 	iOpened = EFalse; | 
|         |    344 	iClosed = EFalse; | 
|         |    345 	iNewElement = NULL; | 
|         |    346 	iParentElement = NULL; | 
|         |    347 	delete iUTF8EdgeBuffer; | 
|         |    348 	iUTF8EdgeBuffer = NULL; | 
|         |    349 	delete iBomBuffer; | 
|         |    350 	iBomBuffer = NULL; | 
|         |    351  | 
|         |    352 	CreateDocumentL(); | 
|         |    353 	iState = KDetermineCharset; | 
|         |    354 	} | 
|         |    355  | 
|         |    356 //================================================================================== | 
|         |    357 TBool CMDXMLParser::DetectFileType() | 
|         |    358 // | 
|         |    359 // Detects the type of a data source - can be Unicode, UTF-8 or ASCII (because ASCII is | 
|         |    360 // a subset of UTF-8). | 
|         |    361 // If the file is empty it is assumed to be Utf-8. | 
|         |    362 	{ | 
|         |    363 	TBuf8<3> bom; | 
|         |    364  | 
|         |    365 	// Read the first 3 bytes of the file.  These contain any BOM present.  If it turns out | 
|         |    366 	// there's not a bom we leave the pointer untouched so we can parse these bytes | 
|         |    367 	// as usual.   | 
|         |    368 	if(iInputBufferPtr.Length() < 3) | 
|         |    369 		return EFalse; | 
|         |    370 	else | 
|         |    371 		bom.Copy(iInputBufferPtr.Left(3)); | 
|         |    372  | 
|         |    373 	TInt hichar = (CEditableText::EByteOrderMark & 0xFF00)>>8; | 
|         |    374 	TInt lochar = CEditableText::EByteOrderMark & 0xFF; | 
|         |    375  | 
|         |    376 	if((bom[0] == 0xEF) && (bom[1] == 0xBB) && (bom[2] == 0xBF)) | 
|         |    377 		{ | 
|         |    378 		// Utf-8 with a bom.  We don't want to parse the bom, so add 3 bytes offset to the read pos. | 
|         |    379 		iBytesPerChar = 1; | 
|         |    380 		iNextChar = 3; | 
|         |    381 		} | 
|         |    382 	else | 
|         |    383 		{ | 
|         |    384 		if((bom[0] == lochar) && (bom[1] == hichar)) | 
|         |    385 			{ | 
|         |    386 			// Little Endian Unicode.  Move the read position on 2 bytes to ignore the bom. | 
|         |    387 			iBytesPerChar = 2; | 
|         |    388 			// would normally skip first 2 characters | 
|         |    389 			iNextChar = 2; | 
|         |    390 			} | 
|         |    391 		else if((bom[0] == hichar) && (bom[1] == lochar)) | 
|         |    392 			{ | 
|         |    393 			// We have a bom, but it indicates endianess opposite to that of the platform.  We | 
|         |    394 			// don't currently support this so set an error. | 
|         |    395 			SetError(KErrNotSupported, EXMLFatal); | 
|         |    396 			} | 
|         |    397 		else | 
|         |    398 			{ | 
|         |    399 			// Default to Utf-8 | 
|         |    400 			iBytesPerChar = 1; | 
|         |    401 			} | 
|         |    402 		} | 
|         |    403 	return ETrue; | 
|         |    404 	} | 
|         |    405  | 
|         |    406 //================================================================================== | 
|         |    407  | 
|         |    408 EXPORT_C void CMDXMLParser::DoCancel() | 
|         |    409 // | 
|         |    410 // DoCancel function inherited from CActive base class | 
|         |    411 // | 
|         |    412 	{ | 
|         |    413 	if (iDataSource) | 
|         |    414 	  { | 
|         |    415 	  iDataSource->Disconnect(); | 
|         |    416 	  iDataSource = NULL; | 
|         |    417 	  } | 
|         |    418 	} | 
|         |    419  | 
|         |    420 //================================================================================== | 
|         |    421  | 
|         |    422 EXPORT_C TInt CMDXMLParser::RunError(TInt aError) | 
|         |    423 // | 
|         |    424 // RunError function inherited from CActive base class - intercepts any Leave from | 
|         |    425 // the RunL() function, sets an appropriate errorcode and calls ParseFileCompleteL | 
|         |    426 // | 
|         |    427 	{ | 
|         |    428 	if(iDataSource) | 
|         |    429 		{ | 
|         |    430 		iDataSource->Disconnect(); | 
|         |    431 		iDataSource = NULL; | 
|         |    432 		} | 
|         |    433  | 
|         |    434 	iSeverity = EXMLFatal; | 
|         |    435 	iError = aError; | 
|         |    436 	if (iFileToParse) | 
|         |    437 		{ | 
|         |    438 		delete iFileToParse; | 
|         |    439 		iFileToParse = NULL; | 
|         |    440 		} | 
|         |    441 	else if( iFileSource==NULL ) | 
|         |    442 		{ | 
|         |    443 		// iFileSource is not set so the ownership of the file handle has not been passed | 
|         |    444 		iFileHandleToParse.Close(); | 
|         |    445 		} | 
|         |    446  | 
|         |    447 	__ASSERT_DEBUG(iParserObserver != NULL, Panic(ENullMemVarParserObserver)); | 
|         |    448 	TRAPD(err, iParserObserver->ParseFileCompleteL()); | 
|         |    449 	return err; | 
|         |    450 	} | 
|         |    451  | 
|         |    452 //================================================================================== | 
|         |    453  | 
|         |    454 TBool CMDXMLParser::DoParseLoopL() | 
|         |    455 // | 
|         |    456 // RunL function inherited from CActive base class - carries out the actual parsing. | 
|         |    457 // @leave can Leave due to OOM | 
|         |    458 // | 
|         |    459 	{ | 
|         |    460 	TBuf<1> singleChar; | 
|         |    461 	TGetCharReturn getCharReturn = KError; | 
|         |    462 	TInt error; | 
|         |    463  | 
|         |    464 	while(iSeverity != EXMLFatal && (getCharReturn = GetChar(singleChar), getCharReturn == KCharReturned) ) | 
|         |    465 		{ | 
|         |    466  | 
|         |    467 #if 0	// THIS NEEDS TO BE REMOVED - IT'S A VERY HANDY DEBUGGING TOOL WHEN YOU'RE MANUALLY DOING  | 
|         |    468 		// BYTE ORDERING ON MISALIGNED STREAMS THOUGH... | 
|         |    469 		{ | 
|         |    470 #define DES_AS_8_BIT(str) (TPtrC8((TText8*)((str).Ptr()), (str).Size())) | 
|         |    471  | 
|         |    472 		RFs aRFs; | 
|         |    473 		RFile aFile; | 
|         |    474 		_LIT(KFileName, "c:\\documents\\SMIL_Test_Files\\echoOutput.txt"); | 
|         |    475 		TPtrC file; | 
|         |    476 		TInt err; | 
|         |    477  | 
|         |    478 		file.Set(KFileName); | 
|         |    479  | 
|         |    480 		aRFs.Connect(); | 
|         |    481  | 
|         |    482 		err = aFile.Open(aRFs, file, EFileWrite); | 
|         |    483 		if(err != KErrNone) | 
|         |    484 			err = aFile.Create(aRFs, file, EFileWrite); | 
|         |    485  | 
|         |    486 		err = 0; | 
|         |    487 		aFile.Seek(ESeekEnd, err); | 
|         |    488 		aFile.Write(DES_AS_8_BIT(singleChar)); | 
|         |    489 		aFile.Close(); | 
|         |    490 		aRFs.Close(); | 
|         |    491 		} | 
|         |    492 #endif | 
|         |    493 		if((!iOpened) && singleChar != KXMLStartTag) | 
|         |    494 			{ | 
|         |    495 			HandleTextL(singleChar); | 
|         |    496 			} | 
|         |    497  | 
|         |    498 		if((iOpened) || (singleChar == KXMLStartTag))			 | 
|         |    499 			{ | 
|         |    500 			if(singleChar == KXMLStartTag) | 
|         |    501 				{ | 
|         |    502 				if(iOpened) | 
|         |    503 					{ | 
|         |    504 					if((iSuspiciousCharacter == KErrNotFound)) | 
|         |    505 						{ | 
|         |    506 						iSuspiciousCharacter = iElementTag->Length(); | 
|         |    507 						} | 
|         |    508 					} | 
|         |    509 				else | 
|         |    510 					{ | 
|         |    511 					AddTextL(iParentElement); | 
|         |    512 					iOpened = ETrue; | 
|         |    513 					} | 
|         |    514 				} | 
|         |    515 			else if(singleChar == KXMLEndTag) | 
|         |    516 				{ | 
|         |    517 				if(iSuspiciousCharacter != KErrNotFound) | 
|         |    518 					{ | 
|         |    519 					TPtrC suspiciousSection = iElementTag->Mid(iSuspiciousCharacter); | 
|         |    520 					if( CheckForStartCData(suspiciousSection) == 0 ) | 
|         |    521 						{ | 
|         |    522 						TInt endCDataLen = TPtrC(KXMLEndCDataSection).Length(); | 
|         |    523 						// The suspicious character begins a CDataSection.  Check if | 
|         |    524 						// this End Tag is closing it. | 
|         |    525 						if( suspiciousSection.Right(endCDataLen - 1)  | 
|         |    526 							== TPtrC(KXMLEndCDataSection).Left(endCDataLen - 1) ) | 
|         |    527 							{ | 
|         |    528 							// Any dodgy characters began the CDataSection or were in it | 
|         |    529 							iSuspiciousCharacter = KErrNotFound; | 
|         |    530 							} | 
|         |    531 						} | 
|         |    532 					else if( suspiciousSection.Find(KXMLStartComment) == 0 ) | 
|         |    533 						{ | 
|         |    534 						// The suspicious character begins a comment.  Check if | 
|         |    535 						// this End Tag is closing it. | 
|         |    536 						TInt endCommentLen = TPtrC(KXMLEndComment).Length(); | 
|         |    537 						if( suspiciousSection.Right(endCommentLen - 1)  | 
|         |    538 							== TPtrC(KXMLEndComment).Left(endCommentLen - 1) ) | 
|         |    539 							{ | 
|         |    540 							// Any dodgy characters began the comment or were in it | 
|         |    541 							iSuspiciousCharacter = KErrNotFound; | 
|         |    542 							} | 
|         |    543 						} | 
|         |    544 					else if((CheckForStartCData(*iElementTag) == 0) || (iElementTag->Find(KXMLStartComment) == 0)) | 
|         |    545 						{ | 
|         |    546 						// this tag is a CDataSection or comment, we're allowed < | 
|         |    547 						iSuspiciousCharacter = KErrNotFound; | 
|         |    548 						iClosed = ETrue; | 
|         |    549 						} | 
|         |    550 					else | 
|         |    551 						{ | 
|         |    552 						// The < was spurious, set an error and close the tag as normal | 
|         |    553 						SetError(KErrXMLIllegalCharacter, EXMLWorkable); | 
|         |    554 						iClosed = ETrue; | 
|         |    555 						iSuspiciousCharacter = KErrNotFound; | 
|         |    556 						} | 
|         |    557 					} | 
|         |    558 				else | 
|         |    559 					{ | 
|         |    560 					iClosed = ETrue; | 
|         |    561 					} | 
|         |    562 				} | 
|         |    563  | 
|         |    564 			// ensure descriptor doesn't overflow end and panics | 
|         |    565 			if(iElementTag->Length() == iElementTag->Des().MaxLength()) | 
|         |    566 				{ | 
|         |    567 				iElementTag = iElementTag->ReAllocL(iElementTag->Length() + KNominalTagLength); | 
|         |    568 				} | 
|         |    569  | 
|         |    570 			iElementTag->Des().Append(singleChar); | 
|         |    571  | 
|         |    572 			// if tag is complete and needs adding to the DOM? | 
|         |    573 			if(iClosed) | 
|         |    574 				{ | 
|         |    575 				if(		!CommentL(iParentElement) | 
|         |    576 					&&	!CDataSectionL(iParentElement) | 
|         |    577 					&&	!VersionIDL() | 
|         |    578 					&&	!DocTypeL() | 
|         |    579 					&&	!ProcessingInstructionL(iParentElement) ) | 
|         |    580 					{ | 
|         |    581 					// is this a regular closing tag | 
|         |    582 					if | 
|         |    583 						(iElementTag->Left(2) == KXMLStartEndTag) | 
|         |    584 						{ | 
|         |    585 						error = ParseElementEndTag(*iParentElement, iElementTag->Des()); | 
|         |    586 						if(error == KErrNone) | 
|         |    587 							{ | 
|         |    588 							if(iParentElement->ParentNode() == NULL) | 
|         |    589 								{ | 
|         |    590 								SetError(KErrXMLBadNesting, EXMLIndeterminate); | 
|         |    591 								} | 
|         |    592 							else | 
|         |    593 								{ | 
|         |    594 								iParentElement = (CMDXMLElement*) iParentElement->ParentNode(); | 
|         |    595 								} | 
|         |    596 							} | 
|         |    597 						else if(error == KErrNotFound) | 
|         |    598 							{ | 
|         |    599 							CMDXMLElement* tempElement = (CMDXMLElement*) iParentElement->ParentNode(); | 
|         |    600 							TInt searchResult = KErrNotFound; | 
|         |    601  | 
|         |    602 							while(tempElement != NULL && | 
|         |    603 									searchResult == KErrNotFound && | 
|         |    604 									tempElement->NodeName() != KXMLDocumentElementNodeName) | 
|         |    605 								{ | 
|         |    606 								searchResult = ParseElementEndTag(*tempElement,iElementTag->Des());	 | 
|         |    607 								if(searchResult == KErrNone) | 
|         |    608 									{ | 
|         |    609 									iParentElement = tempElement; | 
|         |    610 									SetError(KErrXMLBadNesting, EXMLIndeterminate); | 
|         |    611 									} | 
|         |    612 								else | 
|         |    613 									{ | 
|         |    614 									tempElement = (CMDXMLElement*) tempElement->ParentNode(); | 
|         |    615 									} | 
|         |    616 								} | 
|         |    617 							if(searchResult != KErrNone) | 
|         |    618 								{ | 
|         |    619 								SetError(KErrXMLBadNesting, EXMLIndeterminate); | 
|         |    620 								} | 
|         |    621 							} | 
|         |    622 						else | 
|         |    623 							{ | 
|         |    624 							SetError(error, EXMLIndeterminate); | 
|         |    625 							} | 
|         |    626 						} | 
|         |    627 					// if a new element start tag or start/end tag | 
|         |    628 					else | 
|         |    629 						{ | 
|         |    630 						// NOTE ParseStartTagL destroys iElementTag | 
|         |    631 						// so following check must be done first | 
|         |    632  | 
|         |    633 						// if not single tag with close | 
|         |    634 						if(!(iElementTag->Right(2) == KXMLEndStartTag)) | 
|         |    635 							{ | 
|         |    636 							iNewElement = ParseStartTagL(); | 
|         |    637 							CleanupStack::PushL(iNewElement); | 
|         |    638 							error = iParentElement->AppendChild(iNewElement); | 
|         |    639  | 
|         |    640 							if(error == KErrNone) | 
|         |    641 								{ | 
|         |    642 								CleanupStack::Pop(); // iNewElement | 
|         |    643 								iParentElement = (CMDXMLElement*) iParentElement->LastChild(); | 
|         |    644 								} | 
|         |    645 							else | 
|         |    646 								{ | 
|         |    647 								SetError(error, EXMLWorkable); | 
|         |    648 								CleanupStack::PopAndDestroy(iNewElement); // iNewElement | 
|         |    649 								} | 
|         |    650 							} | 
|         |    651 						else | 
|         |    652 							{ | 
|         |    653 							iNewElement = ParseStartTagL(); | 
|         |    654 							CleanupStack::PushL(iNewElement); | 
|         |    655 							error = iParentElement->AppendChild(iNewElement); | 
|         |    656  | 
|         |    657 							if(error == KErrNone) | 
|         |    658 								{ | 
|         |    659 								CleanupStack::Pop(iNewElement); // iNewElement | 
|         |    660 								} | 
|         |    661 							else | 
|         |    662 								{ | 
|         |    663 								SetError(error, EXMLWorkable); | 
|         |    664 								CleanupStack::PopAndDestroy(iNewElement); // iNewElement | 
|         |    665 								} | 
|         |    666 							} | 
|         |    667 						} | 
|         |    668 						iEndOfTag = ETrue; | 
|         |    669 					} | 
|         |    670  | 
|         |    671 				if(iEndOfTag) | 
|         |    672 					{ | 
|         |    673 					iEndOfTag = EFalse; | 
|         |    674 					iOpened = iClosed = EFalse; | 
|         |    675 					iElementTag->Des().Zero(); | 
|         |    676  | 
|         |    677 					// reduce size of ElementTag if increased beyond normal limits on last pass | 
|         |    678 					if(iElementTag->Des().MaxLength() > KNominalTagLength) | 
|         |    679 						{ | 
|         |    680 						iElementTag = iElementTag->ReAllocL(KNominalTagLength); | 
|         |    681 						} | 
|         |    682 					} | 
|         |    683 				} | 
|         |    684 			} | 
|         |    685 		}	// END OF WHILE LOOP | 
|         |    686  | 
|         |    687 	if(getCharReturn == KError) | 
|         |    688 		{ | 
|         |    689 		return EFalse; | 
|         |    690 		} | 
|         |    691 	else | 
|         |    692 		{ | 
|         |    693 		//	GetChar returned KWEaitForChar | 
|         |    694 		// GetChar handles pushing the state and requesting more data for us, so we just go active. | 
|         |    695 		return ETrue; | 
|         |    696 		} | 
|         |    697 	} | 
|         |    698  | 
|         |    699  | 
|         |    700  | 
|         |    701  | 
|         |    702 //================================================================================== | 
|         |    703  | 
|         |    704 void CMDXMLParser::RunL() | 
|         |    705 	{ | 
|         |    706 	TRequestStatus* s=&iStatus; | 
|         |    707 	TInt err = s->Int(); | 
|         |    708  | 
|         |    709 	switch(iState) | 
|         |    710 		{ | 
|         |    711 	case KInitFromFile: | 
|         |    712 		delete iFileSource; | 
|         |    713 		iFileSource = NULL; | 
|         |    714 		if( iFileToParse == NULL ) | 
|         |    715 			{ | 
|         |    716 			// iFileToParse is not set, file was passed by open file handle. | 
|         |    717 			iFileSource = CMDXMLParserFileDataSource::NewL(iFileHandleToParse);			 | 
|         |    718 			} | 
|         |    719 		else | 
|         |    720 			{ | 
|         |    721 			iFileSource = CMDXMLParserFileDataSource::NewL(iRFs, *iFileToParse); | 
|         |    722  | 
|         |    723 			delete iFileToParse; | 
|         |    724 			iFileToParse = NULL; | 
|         |    725 			} | 
|         |    726  | 
|         |    727 		ParseSource(iFileSource);	// will go active itself  | 
|         |    728 		break; | 
|         |    729  | 
|         |    730 	case KDetermineCharset: | 
|         |    731 		if(!iBytesPerChar) | 
|         |    732 			{ | 
|         |    733 			if(DetectFileType()) | 
|         |    734 				{ | 
|         |    735 				iState = KParseData; | 
|         |    736 				SetActive(); | 
|         |    737 				User::RequestComplete(s, KErrNone); | 
|         |    738 				} | 
|         |    739 			else | 
|         |    740 				{ | 
|         |    741 				if(!iBomBuffer) | 
|         |    742 					{ | 
|         |    743 					iBomBuffer = HBufC8::NewL(KUTF8EdgeBufferLen); | 
|         |    744 					} | 
|         |    745  | 
|         |    746 				TPtr8 bomDes(iBomBuffer->Des()); | 
|         |    747 				TInt newLength = bomDes.Length() + iCurrentInputBufferLen; | 
|         |    748 				iBomBuffer->ReAlloc(newLength); | 
|         |    749 				 | 
|         |    750 				bomDes.Append(iInputBufferPtr); | 
|         |    751 				if(iBomBuffer->Length() >=3) | 
|         |    752 					{ | 
|         |    753 					iInputBufferPtr.Set(bomDes); | 
|         |    754 					iCurrentInputBufferLen = newLength; | 
|         |    755  | 
|         |    756 					SetActive(); | 
|         |    757 					User::RequestComplete(s, KErrNone); | 
|         |    758 					} | 
|         |    759 				else | 
|         |    760 					{ | 
|         |    761 					GetMoreData(); | 
|         |    762 					} | 
|         |    763 				} | 
|         |    764 			} | 
|         |    765 		else | 
|         |    766 			{ | 
|         |    767 			iState = KParseData; | 
|         |    768 			SetActive(); | 
|         |    769 			User::RequestComplete(s, KErrNone); | 
|         |    770 			} | 
|         |    771 		break; | 
|         |    772  | 
|         |    773 	case KWaitingForData: | 
|         |    774 		switch(err) | 
|         |    775 			{ | 
|         |    776 		case MMDXMLParserDataProvider::KMoreData: | 
|         |    777 			// We got more data this time, make sure all the parameters are correct. | 
|         |    778 			iCurrentInputBufferLen = iInputBufferPtr.Length();				 | 
|         |    779  | 
|         |    780 			iState = iPreviousState; | 
|         |    781 			SetActive(); | 
|         |    782 			User::RequestComplete(s, KErrNone); | 
|         |    783 			break; | 
|         |    784  | 
|         |    785 		case MMDXMLParserDataProvider::KDataStreamEnd: | 
|         |    786 			iState = KFinished; | 
|         |    787 			SetActive(); | 
|         |    788 			User::RequestComplete(s, KErrNone); | 
|         |    789 			break; | 
|         |    790  | 
|         |    791 		default: | 
|         |    792 		case MMDXMLParserDataProvider::KDataStreamError: | 
|         |    793 			User::Leave(KErrCorrupt); | 
|         |    794 			break; | 
|         |    795 			} | 
|         |    796  | 
|         |    797 		break; | 
|         |    798  | 
|         |    799 	case KParseData: | 
|         |    800 		if(!iParentElement)	// initialise the parsing | 
|         |    801 			{ | 
|         |    802 			iOpened = EFalse; | 
|         |    803 			iClosed = EFalse; | 
|         |    804 			// If we're going through the tag and find a < we don't know whether | 
|         |    805 			// it will be valid (eg it starts a CDataSection) or whether it's an | 
|         |    806 			// illegal character.  Store its index so that when we're a bit further | 
|         |    807 			// along in the string we can check whether it was allowed and if not  | 
|         |    808 			// set an Illegal Character error. | 
|         |    809 			delete iNewElement; | 
|         |    810 			iNewElement = NULL; | 
|         |    811 			 | 
|         |    812 			__ASSERT_DEBUG(iXMLDoc != NULL, Panic(ENullMemVarXMLDoc)); | 
|         |    813 			iParentElement = iXMLDoc->DocumentElement(); | 
|         |    814  | 
|         |    815 			delete iElementTag; | 
|         |    816 			iElementTag = NULL; | 
|         |    817 			iElementTag = HBufC::NewL(KNominalTagLength); | 
|         |    818 			} | 
|         |    819  | 
|         |    820 		if(!iBytesPerChar) | 
|         |    821 			{ | 
|         |    822 			// assume ascii/UTF8 | 
|         |    823 			iBytesPerChar = 1; | 
|         |    824 			} | 
|         |    825  | 
|         |    826 		if(!DoParseLoopL()) | 
|         |    827 			iState = KFinished; | 
|         |    828  | 
|         |    829 			break; | 
|         |    830  | 
|         |    831 	case KFinished: | 
|         |    832 		// Check for any errors that we can pick up now, like missing doctype, or incomplete content | 
|         |    833 		CheckForErrors(); | 
|         |    834  | 
|         |    835 		// we want to leave this instance in a safe state where it can be restarted again with a single call to ParseSource. | 
|         |    836 		// cannot delete this element, as it belongs to the document... | 
|         |    837 		iParentElement = NULL; | 
|         |    838 		iState = KDetermineCharset; | 
|         |    839  | 
|         |    840 		iDataSource->Disconnect(); | 
|         |    841 		iDataSource=NULL; | 
|         |    842 		__ASSERT_DEBUG(iParserObserver != NULL, Panic(ENullMemVarParserObserver)); | 
|         |    843 		iParserObserver->ParseFileCompleteL(); | 
|         |    844 		break; | 
|         |    845  | 
|         |    846 	default: | 
|         |    847 		User::Leave(KErrUnknown); | 
|         |    848 		break; | 
|         |    849 		} | 
|         |    850 	} | 
|         |    851  | 
|         |    852 void CMDXMLParser::CheckForErrors() | 
|         |    853 	{ | 
|         |    854 	if(iError == KErrNone) | 
|         |    855 		{ | 
|         |    856 		if(iParentElement) | 
|         |    857 			{ | 
|         |    858 			// if iParentElement is not pointing to dummy root node, there has been a problem | 
|         |    859 			if( (iParentElement == NULL) || (iParentElement->NodeName() != KXMLDocumentElementNodeName) ) | 
|         |    860 				{ | 
|         |    861 				SetError(KErrXMLIncomplete, EXMLWorkable); | 
|         |    862 				} | 
|         |    863 			else if(!iParentElement->CheckChildren()) | 
|         |    864 				{ | 
|         |    865 				SetError(KErrXMLInvalidChild, EXMLWorkable); | 
|         |    866 				} | 
|         |    867 			else if(iParentElement->FirstChild() != NULL) | 
|         |    868 				{ | 
|         |    869 				// multiple real (not dummy) root elements | 
|         |    870 				TInt count = 0; | 
|         |    871 				CMDXMLNode* iterator = iParentElement->FirstChild(); | 
|         |    872 				do | 
|         |    873 					{ | 
|         |    874 					if(iterator->NodeType() == CMDXMLNode::EElementNode) | 
|         |    875 						{ | 
|         |    876 						count++; | 
|         |    877 						} | 
|         |    878 					iterator = iterator->NextSibling(); | 
|         |    879 					} | 
|         |    880 				while(iterator != NULL); | 
|         |    881  | 
|         |    882 				if(count != 1) | 
|         |    883 					{ | 
|         |    884 					SetError(KErrXMLMultipleRootElements, EXMLWorkable); | 
|         |    885 					} | 
|         |    886 				} | 
|         |    887 			} | 
|         |    888 		} | 
|         |    889 	if(iError == KErrNone && !iDocTypeSet) | 
|         |    890 		{ | 
|         |    891 		SetError(KErrXMLMissingDocTypeTag, EXMLWorkable); | 
|         |    892 		} | 
|         |    893  | 
|         |    894 	if(iError == KErrNone && !iVersionSet) | 
|         |    895 		{ | 
|         |    896 		SetError(KErrXMLMissingVersionTag, EXMLWorkable); | 
|         |    897 		} | 
|         |    898 	} | 
|         |    899  | 
|         |    900  | 
|         |    901 void CMDXMLParser::CreateDocumentL() | 
|         |    902 // | 
|         |    903 // Creates a generic or DTD-specific document object | 
|         |    904 // @leave can Leave due to OOM | 
|         |    905 // | 
|         |    906 	{ | 
|         |    907 	delete iXMLDoc; | 
|         |    908 	iXMLDoc = NULL; | 
|         |    909  | 
|         |    910 	if (iDtdRepresentation != NULL) | 
|         |    911 		iXMLDoc = CMDXMLDocument::NewL(*iDtdRepresentation); | 
|         |    912 	else | 
|         |    913 		iXMLDoc = CMDXMLDocument::NewL(); | 
|         |    914 	} | 
|         |    915  | 
|         |    916  | 
|         |    917 //================================================================================== | 
|         |    918  | 
|         |    919 TBool CMDXMLParser::DocTypeL() | 
|         |    920 // | 
|         |    921 // @return Returns true if the current tag is a doctype tag and sets the | 
|         |    922 // Document DocType member accordingly on the first pass of this function. | 
|         |    923 // | 
|         |    924 	{ | 
|         |    925 	TBool returnValue = EFalse; | 
|         |    926 	TInt tagIdLen = TPtrC(KXMLDocumentTypes).Length(); | 
|         |    927  | 
|         |    928 	__ASSERT_DEBUG(iElementTag != NULL, Panic(ENullMemVarElementTag)); | 
|         |    929  | 
|         |    930 	if(iElementTag->Length() > tagIdLen | 
|         |    931 			&& iElementTag->Left(tagIdLen) == KXMLDocumentTypes) | 
|         |    932 		{ | 
|         |    933 		if(iDocTypeSet) | 
|         |    934 			{ | 
|         |    935 			SetError(KErrXMLDuplicateDocTypeTags, EXMLWorkable); | 
|         |    936 			} | 
|         |    937 		else | 
|         |    938 			{ | 
|         |    939 			iXMLDoc->SetDocTypeTagL(iElementTag->Des()); | 
|         |    940 			iDocTypeSet = ETrue; | 
|         |    941 			} | 
|         |    942 		returnValue = ETrue; | 
|         |    943 		iEndOfTag = ETrue; | 
|         |    944 		} | 
|         |    945  | 
|         |    946 	return returnValue; | 
|         |    947 	} | 
|         |    948  | 
|         |    949 //================================================================================== | 
|         |    950  | 
|         |    951 TBool CMDXMLParser::ProcessingInstructionL(CMDXMLElement* aParentElement) | 
|         |    952 // | 
|         |    953 // creates a new processing instruction if necessary and adds to document | 
|         |    954 // @return Returns true if the current tag is a processing instruction | 
|         |    955 // | 
|         |    956 	{ | 
|         |    957 	TBool returnValue = EFalse; | 
|         |    958 	TInt startPILen = TPtrC(KXMLStartProcessingInstruction).Length(); | 
|         |    959 	TInt endPILen = TPtrC(KXMLEndProcessingInstruction).Length(); | 
|         |    960  | 
|         |    961 	__ASSERT_DEBUG(iElementTag != NULL, Panic(ENullMemVarElementTag)); | 
|         |    962  | 
|         |    963 	if((iElementTag->Left(startPILen) == KXMLStartProcessingInstruction) && | 
|         |    964 		(iElementTag->Right(endPILen) == KXMLEndProcessingInstruction)) | 
|         |    965 		{ | 
|         |    966 		if(aParentElement != NULL) | 
|         |    967 			{ | 
|         |    968 			CMDXMLProcessingInstruction* inst = CMDXMLProcessingInstruction::NewLC(iXMLDoc); | 
|         |    969  | 
|         |    970 			TPtrC instStr = iElementTag->Des().Mid(startPILen, | 
|         |    971 				iElementTag->Length() - (startPILen + endPILen)); | 
|         |    972 			inst->SetDataL(instStr); | 
|         |    973  | 
|         |    974 			__ASSERT_DEBUG(aParentElement != NULL, Panic(ENullParameterParentElement)); | 
|         |    975 			TInt error = aParentElement->AppendChild(inst); | 
|         |    976 			CleanupStack::Pop(inst); | 
|         |    977  | 
|         |    978 			if(error != KErrNone) | 
|         |    979 				{ | 
|         |    980 				SetError(error, EXMLWorkable); | 
|         |    981 				} | 
|         |    982 			} | 
|         |    983  | 
|         |    984 		returnValue = ETrue; | 
|         |    985 		iEndOfTag = ETrue; | 
|         |    986 		} | 
|         |    987  | 
|         |    988 	return returnValue; | 
|         |    989 	} | 
|         |    990  | 
|         |    991  | 
|         |    992 //================================================================================== | 
|         |    993  | 
|         |    994 TBool CMDXMLParser::CDataSectionL(CMDXMLElement* aParentElement) | 
|         |    995 // | 
|         |    996 // creates a new CDataSection if necessary and adds to document | 
|         |    997 // @return Returns true if the current tag is a CDataSection | 
|         |    998 // | 
|         |    999 	{ | 
|         |   1000 	TBool returnValue = EFalse; | 
|         |   1001 	TInt instLen = TPtrC(KXMLStartCDataSection).Length(); | 
|         |   1002 	TInt endCDataLen = TPtrC(KXMLEndCDataSection).Length(); | 
|         |   1003  | 
|         |   1004 	__ASSERT_DEBUG(iElementTag != NULL, Panic(ENullMemVarElementTag)); | 
|         |   1005  | 
|         |   1006 	if (iElementTag->Left(instLen) == KXMLStartCDataSection)  | 
|         |   1007 		{ | 
|         |   1008 		returnValue = ETrue; | 
|         |   1009 		if ((iElementTag->Right(endCDataLen) == KXMLEndCDataSection) && (aParentElement != NULL)) | 
|         |   1010 			{ | 
|         |   1011 			CMDXMLCDATASection* inst = CMDXMLCDATASection::NewLC(iXMLDoc); | 
|         |   1012  | 
|         |   1013 			TPtrC instStr = iElementTag->Des().Mid(instLen, | 
|         |   1014 				iElementTag->Length() - (instLen + endCDataLen)); | 
|         |   1015 			inst->SetDataL(instStr); | 
|         |   1016  | 
|         |   1017 			__ASSERT_DEBUG(aParentElement != NULL, Panic(ENullParameterParentElement)); | 
|         |   1018 			TInt error = aParentElement->AppendChild(inst); | 
|         |   1019 			CleanupStack::Pop(); // inst | 
|         |   1020  | 
|         |   1021 			if(error != KErrNone) | 
|         |   1022 				{ | 
|         |   1023 				SetError(error, EXMLWorkable); | 
|         |   1024 				} | 
|         |   1025 			} | 
|         |   1026 		iEndOfTag = ETrue; | 
|         |   1027 		} | 
|         |   1028  | 
|         |   1029 	return returnValue; | 
|         |   1030 	} | 
|         |   1031  | 
|         |   1032  | 
|         |   1033 //================================================================================== | 
|         |   1034  | 
|         |   1035 TBool CMDXMLParser::VersionIDL() | 
|         |   1036 // | 
|         |   1037 // @return returns true if the current tag is a version id tag and sets the | 
|         |   1038 // Document Version member accordingly on the first pass of this function. | 
|         |   1039 // | 
|         |   1040 	{ | 
|         |   1041 	TBool returnValue = EFalse; | 
|         |   1042 	TInt tagIdLen = TPtrC(KXMLVersion).Length(); | 
|         |   1043  | 
|         |   1044 	__ASSERT_DEBUG(iElementTag != NULL, Panic(ENullMemVarElementTag)); | 
|         |   1045  | 
|         |   1046 	if(iElementTag->Length() > tagIdLen | 
|         |   1047 			&& iElementTag->Left(tagIdLen) == KXMLVersion) | 
|         |   1048 		{ | 
|         |   1049 		if(iVersionSet) | 
|         |   1050 			{ | 
|         |   1051 			SetError(KErrXMLDuplicateVersionTags, EXMLWorkable); | 
|         |   1052 			} | 
|         |   1053 		else | 
|         |   1054 			{ | 
|         |   1055 			iXMLDoc->SetVersionTagL(iElementTag->Des()); | 
|         |   1056 			iVersionSet = ETrue; | 
|         |   1057 			} | 
|         |   1058 		returnValue = ETrue; | 
|         |   1059 		iEndOfTag = ETrue; | 
|         |   1060 		} | 
|         |   1061  | 
|         |   1062 	return returnValue; | 
|         |   1063 	} | 
|         |   1064  | 
|         |   1065 //================================================================================== | 
|         |   1066  | 
|         |   1067 TBool CMDXMLParser::CommentL(CMDXMLElement* aParentElement) | 
|         |   1068 // | 
|         |   1069 // creates a new comment if necessary and adds to document | 
|         |   1070 // @return returns true if the current tag is a comment tag | 
|         |   1071 // | 
|         |   1072 	{ | 
|         |   1073 	TBool returnValue = EFalse; | 
|         |   1074 	TInt commentLen = TPtrC(KXMLStartComment).Length(); | 
|         |   1075 	TInt endCommentLen = TPtrC(KXMLEndComment).Length(); | 
|         |   1076  | 
|         |   1077 	__ASSERT_DEBUG(iElementTag != NULL, Panic(ENullMemVarElementTag)); | 
|         |   1078  | 
|         |   1079 	if (iElementTag->Left(commentLen) == KXMLStartComment)  | 
|         |   1080 		{ | 
|         |   1081 		returnValue = ETrue; | 
|         |   1082 		if ((aParentElement != NULL) && (iElementTag->Right(endCommentLen) == KXMLEndComment)) | 
|         |   1083 			{ | 
|         |   1084 			CMDXMLComment* comment = CMDXMLComment::NewLC(iXMLDoc); | 
|         |   1085  | 
|         |   1086 			TPtrC commentStr = iElementTag->Des().Mid(commentLen, | 
|         |   1087 				iElementTag->Length() - (commentLen + endCommentLen)); | 
|         |   1088 			comment->SetDataL(commentStr); | 
|         |   1089  | 
|         |   1090 			__ASSERT_DEBUG(aParentElement != NULL, Panic(ENullParameterParentElement)); | 
|         |   1091 			TInt error  = aParentElement->AppendChild(comment); | 
|         |   1092 			CleanupStack::Pop(); // comment | 
|         |   1093  | 
|         |   1094 			if(error != KErrNone) | 
|         |   1095 				{ | 
|         |   1096 				SetError(error, EXMLWorkable); | 
|         |   1097 				} | 
|         |   1098 			iEndOfTag = ETrue; | 
|         |   1099 			} | 
|         |   1100 		} | 
|         |   1101  | 
|         |   1102 	return returnValue; | 
|         |   1103 	} | 
|         |   1104  | 
|         |   1105 //================================================================================== | 
|         |   1106  | 
|         |   1107 EXPORT_C void CMDXMLParser::SetSourceCharacterWidth(TMDXMLParserInputCharWidth aWidth) | 
|         |   1108 	{ | 
|         |   1109 	iBytesPerChar = aWidth; | 
|         |   1110 	} | 
|         |   1111  | 
|         |   1112 //================================================================================== | 
|         |   1113  | 
|         |   1114 void CMDXMLParser::GetMoreData() | 
|         |   1115 	{ | 
|         |   1116  | 
|         |   1117 	// Prepare these variables. | 
|         |   1118 	iNextChar = 0;					// reading from the start of the buffer | 
|         |   1119 	iCurrentInputBufferLen = 0;		// we have no characters in the buffer | 
|         |   1120 	iUnicodeConversion.Zero();		// we have no characters in our UTF8->Unicode Conversion buffer. | 
|         |   1121 	iUnicodeConversionLen = 0; | 
|         |   1122 	iUnicodeReadPos = 0; | 
|         |   1123  | 
|         |   1124 	// Request more data from the data provider | 
|         |   1125 	__ASSERT_DEBUG(iDataSource != NULL, Panic(ENullMemVarDataSource)); | 
|         |   1126 	iDataSource->GetData(iInputBufferPtr, iStatus); | 
|         |   1127 	SetActive(); | 
|         |   1128 	iPreviousState = iState; | 
|         |   1129 	iState = KWaitingForData; | 
|         |   1130 	} | 
|         |   1131  | 
|         |   1132 //================================================================================== | 
|         |   1133  | 
|         |   1134 CMDXMLParser::TGetCharReturn CMDXMLParser::GetDoubleByteChar(TDes& aChar) | 
|         |   1135 	// when inputing we have a pointer to an 8 bit buffer (iInputBufferPtr), for unicode | 
|         |   1136 	// input we point a 16 bit descriptor (tempUnicodeInput) at the 8 bit buffer to | 
|         |   1137 	// enable us to read the 2 x 8 bit chars as a single 16 bit char. | 
|         |   1138 	// However it isn't always this simple as the data provider interface makes no guarantees | 
|         |   1139 	// on the alignment of this data. It's perfectly possible for it to end up with a unicode | 
|         |   1140 	// character where the high byte comes from the previous buffer and the low byte comes from | 
|         |   1141 	// the current one.  This will put the rest of the current buffer out of line, and also all | 
|         |   1142 	// subsequent buffers unless an odd length buffer is provided.  Hopfully this won't happen often. | 
|         |   1143 	{ | 
|         |   1144 	aChar.Zero(); | 
|         |   1145  | 
|         |   1146 	if(iUnicodeInputMisaligned) | 
|         |   1147 		{ | 
|         |   1148 		TUint16 tempOut; | 
|         |   1149 		TUint8* tempRead; | 
|         |   1150 		tempRead = (TUint8*)(iInputBufferPtr.Ptr()) + iNextChar; | 
|         |   1151  | 
|         |   1152 		if(iCurrentInputBufferLen - iNextChar >=1) | 
|         |   1153 		{ | 
|         |   1154 			// if we saved a byte last time, lets use that first | 
|         |   1155 			if(iSpareChar.Length()) | 
|         |   1156 				{ | 
|         |   1157 				tempOut = iSpareChar[0]; | 
|         |   1158 				iSpareChar.Zero(); | 
|         |   1159 				} | 
|         |   1160 			else if(iCurrentInputBufferLen - iNextChar >=2) | 
|         |   1161 				{ | 
|         |   1162 				// we didn't save a byte, so we read from the stream. | 
|         |   1163 				tempOut = *tempRead; | 
|         |   1164 				tempRead++; | 
|         |   1165 				iNextChar++; | 
|         |   1166 				} | 
|         |   1167 			else | 
|         |   1168 				{ | 
|         |   1169 				// our input stream must have been an odd length - this might cause alignment problems,  | 
|         |   1170 				// so we need to start reading bytewise for a while | 
|         |   1171 				iUnicodeInputMisaligned = ETrue; | 
|         |   1172  | 
|         |   1173 				TUint8* tempRead = (TUint8*)(iInputBufferPtr.Ptr()) + iNextChar; | 
|         |   1174 				TUint16 tempVal = (TUint16)(*tempRead << 8); | 
|         |   1175 				iSpareChar.Copy(&tempVal,1); | 
|         |   1176  | 
|         |   1177 				GetMoreData(); | 
|         |   1178 				return KWaitForChar; | 
|         |   1179  | 
|         |   1180 				} | 
|         |   1181  | 
|         |   1182 			// second byte (high byte) of our output comes from the input stream in all cases. | 
|         |   1183 			tempOut |= ((*tempRead & 0xFF) << 8); | 
|         |   1184 			iNextChar++; | 
|         |   1185  | 
|         |   1186 			TPtrC16 readDes(&tempOut, 1); | 
|         |   1187 			aChar = readDes.Left(1); | 
|         |   1188 			} | 
|         |   1189 		} | 
|         |   1190 	else if(iCurrentInputBufferLen - iNextChar >= 2) | 
|         |   1191 		{ | 
|         |   1192 		// we may be in a position where we don't know we're going to lose a byte | 
|         |   1193 		// so we'll test for that ahead of time, and then handle that in the normal way | 
|         |   1194  | 
|         |   1195 		// if we execute this, it means that we have two bytes available to read. | 
|         |   1196 		const TUint16* word = reinterpret_cast<const TUint16*>((iInputBufferPtr.Ptr() + iNextChar)); | 
|         |   1197 		TPtrC16 tempUnicodeInput(word, 2); | 
|         |   1198 		aChar = tempUnicodeInput.Left(1); | 
|         |   1199 		iNextChar+=2; | 
|         |   1200 		return KCharReturned; | 
|         |   1201 		} | 
|         |   1202 	 | 
|         |   1203 	TInt bytesRemaining = iCurrentInputBufferLen - iNextChar; | 
|         |   1204  | 
|         |   1205 	switch(bytesRemaining) | 
|         |   1206 		{ | 
|         |   1207 		case 1: | 
|         |   1208 			{ | 
|         |   1209 			// our input stream must have been an odd length - this might cause alignment problems,  | 
|         |   1210 			// so we need to start reading bytewise for a while | 
|         |   1211  | 
|         |   1212 			TUint8* tempRead = (TUint8*)(iInputBufferPtr.Ptr()) + iNextChar; | 
|         |   1213 			TUint16 tempVal = *tempRead; | 
|         |   1214 			iSpareChar.Copy(&tempVal,1); | 
|         |   1215 			iUnicodeInputMisaligned = ETrue; | 
|         |   1216 			iNextChar++; | 
|         |   1217 			if(!aChar.Length()) | 
|         |   1218 				{ | 
|         |   1219 				GetMoreData(); | 
|         |   1220 				return KWaitForChar; | 
|         |   1221 				} | 
|         |   1222 			} | 
|         |   1223 			break; | 
|         |   1224 		case 0: | 
|         |   1225 			{ | 
|         |   1226 			// we're at the end of this block, and it's turned out to be re-aligned. | 
|         |   1227 			// we can read subsequent blocks in 16-bit chunks. | 
|         |   1228 			iUnicodeInputMisaligned = EFalse; | 
|         |   1229 			} | 
|         |   1230 			break; | 
|         |   1231 		} | 
|         |   1232  | 
|         |   1233 	return KCharReturned; | 
|         |   1234 	} | 
|         |   1235 	 | 
|         |   1236 //================================================================================== | 
|         |   1237  | 
|         |   1238 CMDXMLParser::TGetCharReturn CMDXMLParser::GetSingleByteChar(TDes& aChar) | 
|         |   1239 	{ | 
|         |   1240 	// We have UTF8/ASCII Source, and we must need to convert some more if we got here. | 
|         |   1241 	iUnicodeConversion.Zero(); | 
|         |   1242 	iUnicodeConversionLen = 0; | 
|         |   1243 	iUnicodeReadPos = 0; | 
|         |   1244  | 
|         |   1245 	// if we are not operating out of the edge buffer yet, work on the real one | 
|         |   1246 	if(!iUTF8EdgeBuffer) | 
|         |   1247 		{ | 
|         |   1248 		// This is an 8 bit encoding, probably UTF-8, but could be ASCII.  Because | 
|         |   1249 		// ASCII is valid UTF-8 we can just convert what we have to Unicode. | 
|         |   1250 		// We're going to convert a number of characters at a time here. | 
|         |   1251 		TInt inputBytesRemaining = iCurrentInputBufferLen - iNextChar; | 
|         |   1252 		TInt convResult; | 
|         |   1253 		TPtrC8 tempPtr( (TUint8*)(iInputBufferPtr.Ptr()) + iNextChar, inputBytesRemaining ); | 
|         |   1254  | 
|         |   1255 		convResult = CnvUtfConverter::ConvertToUnicodeFromUtf8(iUnicodeConversion, tempPtr); | 
|         |   1256 		if((convResult >= 0) || (convResult == KErrCorrupt)) | 
|         |   1257 			{ | 
|         |   1258 			// Sometimes the UTF8 decoder might return corrupt if it only gets a single character | 
|         |   1259 			// in this case we ignore the error and report that we have converted 0 characters | 
|         |   1260 			if (convResult == KErrCorrupt) | 
|         |   1261 				convResult = tempPtr.Length(); | 
|         |   1262  | 
|         |   1263 			// This is the number of bytes converted. | 
|         |   1264 			// Keep an eye out in case there is no change in the character consumed count. | 
|         |   1265 			TInt bytesConverted = inputBytesRemaining - convResult; | 
|         |   1266  | 
|         |   1267 			// We consumed characters.  Make our input buffer read position correct. | 
|         |   1268 			iNextChar += bytesConverted; | 
|         |   1269  | 
|         |   1270 			// Make our intermediate buffering correct and return the first character out of our buffer | 
|         |   1271 			// subsequent calls will just return characters from this buffer. | 
|         |   1272 			iUnicodeConversionLen = iUnicodeConversion.Length(); | 
|         |   1273 			aChar = iUnicodeConversion.Left(1); | 
|         |   1274 			iUnicodeReadPos = 1; | 
|         |   1275  | 
|         |   1276 			if(convResult && convResult < KUTF8EdgeBufferLen) | 
|         |   1277 				{ | 
|         |   1278 				TUint8* multiByteCheck = (TUint8*)(iInputBufferPtr.Ptr()) + iNextChar; | 
|         |   1279  | 
|         |   1280 				// There is a possibility that we've got an edge case here | 
|         |   1281 				//check if our left over character is in fact UTF8. | 
|         |   1282 				if((0x80 & *multiByteCheck) != 0) | 
|         |   1283 					{ | 
|         |   1284 					// Shift 'convResult' characters off into the edge buffer. | 
|         |   1285 					delete iUTF8EdgeBuffer; | 
|         |   1286 					iUTF8EdgeBuffer = HBufC8::New(KUTF8EdgeBufferLen); | 
|         |   1287 					*iUTF8EdgeBuffer = iInputBufferPtr.Right(convResult); | 
|         |   1288  | 
|         |   1289 					TUint8 bitMask = 0x80; | 
|         |   1290 					TInt   byteCount = 0; | 
|         |   1291 					while(bitMask && (bitMask & (iUTF8EdgeBuffer->Des()[0])) != 0) | 
|         |   1292 						{ | 
|         |   1293 						bitMask >>= 1; | 
|         |   1294 						byteCount++; | 
|         |   1295 						}; | 
|         |   1296  | 
|         |   1297 					if(!bitMask) | 
|         |   1298 						{ | 
|         |   1299 						// the utf8 stream appears to be corrupt. | 
|         |   1300 						SetError(KError, EXMLFatal); | 
|         |   1301 						return KError; | 
|         |   1302 						} | 
|         |   1303 					// we need to find byteCount characters to make up the character currently stored in the edge | 
|         |   1304 					// buffer. | 
|         |   1305 					iRequiredUTF8Bytes = byteCount - iUTF8EdgeBuffer->Length(); | 
|         |   1306  | 
|         |   1307 					// set the variables up so that we return any converted characters, and then begin work | 
|         |   1308 					// on the edge buffer (where we've already cached the remaining bytes if any) | 
|         |   1309 					// NOTE: We will return all the characters which we preconverted into iUnicodeConversion *before* | 
|         |   1310 					// we begin dealing with the edge buffer, because of the structure of this function. | 
|         |   1311 					iNextChar = iCurrentInputBufferLen; | 
|         |   1312  | 
|         |   1313 					if (bytesConverted == 0) | 
|         |   1314 						// If no bytes were converted then there is nothing to return, | 
|         |   1315 						// we need to wait for more data and then conbine it with what we have | 
|         |   1316 						// just put on the edge buffer. | 
|         |   1317 						{ | 
|         |   1318 						// need more bytes to finish this character. | 
|         |   1319 						GetMoreData(); | 
|         |   1320 						return KWaitForChar;			 | 
|         |   1321 						} | 
|         |   1322 					} | 
|         |   1323 				} | 
|         |   1324 			} | 
|         |   1325  | 
|         |   1326 		else | 
|         |   1327 			{ | 
|         |   1328 			return KError;	// something failed in the UTF8 Converter. | 
|         |   1329 			} | 
|         |   1330 		} | 
|         |   1331 	else | 
|         |   1332 		{ | 
|         |   1333 		// We are converting the UTF8 Edge Buffer.  We know that in it's current state, it  | 
|         |   1334 		// can't be converted to Unicode. | 
|         |   1335 		// Decide if we have enough characters in our current input stream to convert to an | 
|         |   1336 		// output character (or two) yet. | 
|         |   1337 		 | 
|         |   1338 		if(iUTF8EdgeBuffer->Length() >= KUTF8EdgeBufferLen) | 
|         |   1339 			{ | 
|         |   1340 			// our edge buffer reached the maximum length for a UTF8 character | 
|         |   1341 			// and we haven't managed to convert a unicode output. | 
|         |   1342 			// this means that the input stream is corrupt. | 
|         |   1343 			delete iUTF8EdgeBuffer; | 
|         |   1344 			iUTF8EdgeBuffer = NULL; | 
|         |   1345  | 
|         |   1346 			// Report a fatal error. | 
|         |   1347 			SetError(KError, EXMLFatal); | 
|         |   1348 			return KError; | 
|         |   1349 			} | 
|         |   1350 		else | 
|         |   1351 			{ | 
|         |   1352 			TInt convResult; | 
|         |   1353  | 
|         |   1354 			// we know how many bytes are required in order to complete the utf8 buffer | 
|         |   1355 			TInt bytesAvailable = iCurrentInputBufferLen - iNextChar; | 
|         |   1356  | 
|         |   1357 			if(bytesAvailable >= iRequiredUTF8Bytes) | 
|         |   1358 				{ | 
|         |   1359 				// we have enough bytes to complete this character. | 
|         |   1360 				// Go ahead and convert then return it. | 
|         |   1361 				iUTF8EdgeBuffer->Des().Append(iInputBufferPtr.Mid(iNextChar, iRequiredUTF8Bytes)); | 
|         |   1362 				iUnicodeConversion.Zero(); | 
|         |   1363 				convResult = CnvUtfConverter::ConvertToUnicodeFromUtf8(iUnicodeConversion, iUTF8EdgeBuffer->Des()); | 
|         |   1364 				 | 
|         |   1365 				// regardless if we managed to convert this buffer or not, we don't need it any more. | 
|         |   1366 				delete iUTF8EdgeBuffer; | 
|         |   1367 				iUTF8EdgeBuffer = NULL; | 
|         |   1368  | 
|         |   1369 				// make sure we report any error in the conversion | 
|         |   1370 				if(convResult != 0) | 
|         |   1371 				{ | 
|         |   1372 					// we either incorrectly calculated the required number of bytes or the | 
|         |   1373 					// stream is corrupt.  Either way we have a fatal error. | 
|         |   1374 					SetError(KError, EXMLFatal); | 
|         |   1375 					return KError; | 
|         |   1376 				} | 
|         |   1377  | 
|         |   1378 				// Make our intermediate buffering correct and return the first character out of our buffer | 
|         |   1379 				// subsequent calls will just return characters from this buffer. | 
|         |   1380 				iUnicodeConversionLen = iUnicodeConversion.Length(); | 
|         |   1381 				aChar = iUnicodeConversion.Left(1); | 
|         |   1382 				iUnicodeReadPos = 1; | 
|         |   1383  | 
|         |   1384 				// set up the main input buffers so that the next char comes from the input stream. | 
|         |   1385 				iNextChar += iRequiredUTF8Bytes; | 
|         |   1386 				iRequiredUTF8Bytes = 0; | 
|         |   1387 				} | 
|         |   1388 			else | 
|         |   1389 				{ | 
|         |   1390 				// we haven't got enough bytes to complete this character, store the  | 
|         |   1391 				// available byte(s) and request more data. | 
|         |   1392 				iUTF8EdgeBuffer->Des().Append(iInputBufferPtr.Mid(iNextChar, bytesAvailable)); | 
|         |   1393  | 
|         |   1394 				// Move the next character index on for as many bytes as we have just added to the edge buffer | 
|         |   1395 				iNextChar += bytesAvailable; | 
|         |   1396 				// We can reduce the number of bytes require by the number of bytes added to the edge buffer | 
|         |   1397 				iRequiredUTF8Bytes -= bytesAvailable; | 
|         |   1398  | 
|         |   1399 				// need more bytes to finish this character. | 
|         |   1400 				GetMoreData(); | 
|         |   1401 				return KWaitForChar;			 | 
|         |   1402 				} | 
|         |   1403 			} | 
|         |   1404 		} | 
|         |   1405  | 
|         |   1406 	return KCharReturned; | 
|         |   1407 	} | 
|         |   1408  | 
|         |   1409 //================================================================================== | 
|         |   1410  | 
|         |   1411 CMDXMLParser::TGetCharReturn CMDXMLParser::GetChar(TDes& aChar) | 
|         |   1412 // | 
|         |   1413 // Fetch one character from the input file | 
|         |   1414 // @param aChar the returned character. | 
|         |   1415 // @return returns true if a character returned or false if the file is finished | 
|         |   1416 // | 
|         |   1417 	{ | 
|         |   1418 	// first test - see if we're providing preconverted characters. | 
|         |   1419 	if(iUnicodeConversionLen && iUnicodeReadPos < iUnicodeConversionLen) | 
|         |   1420 		{ | 
|         |   1421 		// return one of the preconverted chars. | 
|         |   1422 		aChar = iUnicodeConversion.Mid(iUnicodeReadPos, 1); | 
|         |   1423 		iUnicodeReadPos++; | 
|         |   1424  | 
|         |   1425 		return KCharReturned; | 
|         |   1426 		} | 
|         |   1427 	 | 
|         |   1428 	// Second test - see if we require more data.  If we have converted data and we require | 
|         |   1429 	// more data, this code is not intelligent enough to request data from the provider | 
|         |   1430 	// early, but that's ok. | 
|         |   1431  | 
|         |   1432 	// Buffer length held as a member variable for performance reasons | 
|         |   1433 	// this function will be accessed thousands of times | 
|         |   1434 	if(iCurrentInputBufferLen <= iNextChar) | 
|         |   1435 		{ | 
|         |   1436 		GetMoreData(); | 
|         |   1437 		return KWaitForChar;	 | 
|         |   1438 		} | 
|         |   1439  | 
|         |   1440 	// return the character, handling any of the buffer shuffling we need to do. | 
|         |   1441 	if(iBytesPerChar == 2) | 
|         |   1442 		return GetDoubleByteChar(aChar); | 
|         |   1443 	else	 | 
|         |   1444 		return GetSingleByteChar(aChar); | 
|         |   1445 	} | 
|         |   1446  | 
|         |   1447 //================================================================================== | 
|         |   1448  | 
|         |   1449 CMDXMLElement* CMDXMLParser::ParseStartTagL() | 
|         |   1450 // | 
|         |   1451 // Parse a start of element tag and create an element with attributes set. | 
|         |   1452 // @return Returns a pointer to the created element | 
|         |   1453 // @leave can Leave due to OOM | 
|         |   1454 // | 
|         |   1455 	{ | 
|         |   1456 	__ASSERT_DEBUG(iElementTag != NULL, Panic(ENullMemVarElementTag)); | 
|         |   1457  | 
|         |   1458 	// there must be at least two angle brackets and a single character to be meaningful | 
|         |   1459 	if(iElementTag->Length() < 3) | 
|         |   1460 		return NULL; | 
|         |   1461  | 
|         |   1462 	CMDXMLElement* newElement = NULL; | 
|         |   1463 	TPtr elementTagPtr = iElementTag->Des(); | 
|         |   1464  | 
|         |   1465 	// remove the angle brackets and trim white space | 
|         |   1466 	if(iElementTag->Right(TPtrC(KXMLEndStartTag).Length()) == KXMLEndStartTag) | 
|         |   1467 		elementTagPtr = iElementTag->Left(iElementTag->Length() - TPtrC(KXMLEndStartTag).Length()); | 
|         |   1468 	else | 
|         |   1469 		elementTagPtr = iElementTag->Left(iElementTag->Length() - TPtrC(KXMLEndTag).Length()); | 
|         |   1470  | 
|         |   1471 	elementTagPtr = iElementTag->Right(iElementTag->Length() - TPtrC(KXMLStartTag).Length()); | 
|         |   1472 	elementTagPtr.Trim(); | 
|         |   1473  | 
|         |   1474 	// find out where the name ends and the attributes begin | 
|         |   1475 	TLex16 element(elementTagPtr); | 
|         |   1476 	element.SkipCharacters(); | 
|         |   1477 	TInt endOfName = element.Offset(); | 
|         |   1478  | 
|         |   1479 	// separate out the name from the attributes | 
|         |   1480 	HBufC* elementName = (iElementTag->Left(endOfName)).AllocLC(); | 
|         |   1481 	TPtr elementNamePtr = elementName->Des(); | 
|         |   1482 	elementNamePtr.TrimRight(); | 
|         |   1483  | 
|         |   1484 	TInt error = KErrNone; | 
|         |   1485  | 
|         |   1486 	__ASSERT_DEBUG(iXMLDoc != NULL, Panic(ENullMemVarXMLDoc)); | 
|         |   1487 	 | 
|         |   1488 	TBool validElement = iXMLDoc->ValidElementNameL(elementNamePtr); | 
|         |   1489 	if(validElement || iStoreInvalid) | 
|         |   1490 		{ | 
|         |   1491 		// remove the actual name from the tag so we only pass on the attributes | 
|         |   1492 		elementTagPtr = iElementTag->Right(iElementTag->Length() - endOfName); | 
|         |   1493 		elementTagPtr.TrimLeft(); | 
|         |   1494 		newElement = CMDXMLElement::NewLC(iXMLDoc->CanElementHaveChildren(elementNamePtr), iXMLDoc, elementNamePtr); | 
|         |   1495  | 
|         |   1496 		error = ParseElementAttributesL(*newElement, elementTagPtr); | 
|         |   1497 		CleanupStack::Pop(); | 
|         |   1498 		} | 
|         |   1499 	if(!validElement) | 
|         |   1500 		{ | 
|         |   1501 		error = KErrXMLInvalidElement; | 
|         |   1502 		} | 
|         |   1503  | 
|         |   1504 	CleanupStack::PopAndDestroy(elementName); // elementName | 
|         |   1505  | 
|         |   1506 	if(error != KErrNone) | 
|         |   1507 		{ | 
|         |   1508 		SetError(error, EXMLWorkable); | 
|         |   1509 		} | 
|         |   1510  | 
|         |   1511 	return newElement; | 
|         |   1512  | 
|         |   1513 	} | 
|         |   1514  | 
|         |   1515  | 
|         |   1516 TInt CMDXMLParser::ParseElementAttributesL(CMDXMLElement& aElement, TDes& aTagToParse) | 
|         |   1517 // | 
|         |   1518 // This function is used to parse the attributes. | 
|         |   1519 // @param aElement The element to which the attributes belong | 
|         |   1520 // @param aTagToParse The tag to be parsed | 
|         |   1521 // @return Returns KErrNone if both attribute name & value are valid  | 
|         |   1522 // KErrXMLBadAttributeName if attribute name is invalid or KErrXMLBadAttributeValue is invalid | 
|         |   1523 // @leave can Leave due to OOM | 
|         |   1524 // | 
|         |   1525 	{ | 
|         |   1526 	TInt error = KErrNone; | 
|         |   1527 	TInt attributeError = KErrNone; | 
|         |   1528 	HBufC* attributeName = NULL; | 
|         |   1529 	HBufC* attributeValue = NULL; | 
|         |   1530 	TBuf<1> attributeDelimiter; // may be " or ' | 
|         |   1531 	TInt offset = KErrNone; | 
|         |   1532  | 
|         |   1533 	offset = aTagToParse.Find(KEqualSign); | 
|         |   1534 	while(offset != KErrNotFound) | 
|         |   1535 		{ | 
|         |   1536 		attributeName = TPtrC(aTagToParse.Left(offset)).AllocLC(); | 
|         |   1537 		TPtr attributeNamePtr = attributeName->Des(); | 
|         |   1538 		attributeNamePtr.TrimRight(); // remove white space that existed between name and equal sign | 
|         |   1539  | 
|         |   1540 		// remove current attribute name and equal sign from string | 
|         |   1541 		aTagToParse = aTagToParse.Right(aTagToParse.Length() - (offset + 1)); | 
|         |   1542 		aTagToParse.TrimLeft(); // remove white space that existed between equal sign and delimiter | 
|         |   1543  | 
|         |   1544 		if(error == KErrNone && aTagToParse.Length() < 2) // a name must be at followed by at least 2 delimiters | 
|         |   1545 			{ | 
|         |   1546 			error = KErrXMLBadAttributeName; | 
|         |   1547 			// In this case, there is insufficient tag left to contain any more attributes | 
|         |   1548 			} | 
|         |   1549 		else if(error == KErrNone && aElement.IsAttributeSpecified(*attributeName)) | 
|         |   1550 			{ | 
|         |   1551 			error = KErrXMLDuplicateAttributeName; | 
|         |   1552 			// We need to remove the attribute value from the tag string or it will be | 
|         |   1553 			// picked up as part of the next attribute name. | 
|         |   1554 			attributeDelimiter = aTagToParse.Left(1); | 
|         |   1555  | 
|         |   1556 			// Check in case we've got a missing " at the beginning of the attribute.  If | 
|         |   1557 			// we do, we need to try a different strategy to find the end of this attribute | 
|         |   1558 			if (attributeDelimiter != KQuotation && attributeDelimiter != KApostrophe) | 
|         |   1559 				{ | 
|         |   1560 				offset = LocateNextAttribute(aTagToParse); | 
|         |   1561 				} | 
|         |   1562 			else | 
|         |   1563 				{ | 
|         |   1564 				// remove start delimiter then search for next one (end delimiter) | 
|         |   1565 				aTagToParse = aTagToParse.Right(aTagToParse.Length() - 1); | 
|         |   1566 				offset = FindDelimiter(aTagToParse, attributeDelimiter); | 
|         |   1567 				} | 
|         |   1568  | 
|         |   1569 			if(offset != KErrNotFound) | 
|         |   1570 				{ | 
|         |   1571 				// remove current attribute value and delimiter | 
|         |   1572 				aTagToParse = aTagToParse.Right(aTagToParse.Length() - (offset + 1)); | 
|         |   1573 				aTagToParse.TrimLeft(); // remove white space that existed between delimiter and next name | 
|         |   1574 				} | 
|         |   1575 			} | 
|         |   1576 		else | 
|         |   1577 			{ | 
|         |   1578 			attributeDelimiter = aTagToParse.Left(1); | 
|         |   1579  | 
|         |   1580 			if (attributeDelimiter != KQuotation && attributeDelimiter != KApostrophe) | 
|         |   1581 				{ | 
|         |   1582 				// This attribute doesn't have a valid delimiter.  Try and find the beginning of the next | 
|         |   1583 				// attribute and just cut this one. | 
|         |   1584 				TInt nextAttribute = LocateNextAttribute(aTagToParse); | 
|         |   1585 				if(nextAttribute > 0) | 
|         |   1586 					{ | 
|         |   1587 					// Add one to next attribute because the offset includes the whitespace before it | 
|         |   1588 					aTagToParse = aTagToParse.Right(aTagToParse.Length() - (nextAttribute + 1)); | 
|         |   1589 					} | 
|         |   1590  | 
|         |   1591 				if (error == KErrNone) | 
|         |   1592 					{ | 
|         |   1593 					error = KErrXMLBadAttributeValue; | 
|         |   1594 					} | 
|         |   1595 				} | 
|         |   1596 			else | 
|         |   1597 				{ | 
|         |   1598 				// remove start delimiter then search for next one (end delimiter) | 
|         |   1599 				aTagToParse = aTagToParse.Right(aTagToParse.Length() - 1); | 
|         |   1600  | 
|         |   1601 				offset = FindDelimiter(aTagToParse, attributeDelimiter); | 
|         |   1602 				if(offset != KErrNotFound) | 
|         |   1603 					{ | 
|         |   1604 					attributeValue = TPtrC(aTagToParse.Left(offset)).AllocLC(); | 
|         |   1605 					TPtr attributeValuePtr = attributeValue->Des(); | 
|         |   1606 					attributeValuePtr.TrimRight(); // remove white space that existed between value and delimiter | 
|         |   1607  | 
|         |   1608 					// remove current attribute value and delimiter | 
|         |   1609 					aTagToParse = aTagToParse.Right(aTagToParse.Length() - (offset + 1)); | 
|         |   1610 					aTagToParse.TrimLeft(); // remove white space that existed between delimiter and next name | 
|         |   1611  | 
|         |   1612 					// Entity convert this attribute | 
|         |   1613 					attributeError = ParseSingleAttributeL(attributeValuePtr); | 
|         |   1614 					if( attributeError != KErrNone && error == KErrNone) | 
|         |   1615 						{ | 
|         |   1616 						error = attributeError; | 
|         |   1617 						} | 
|         |   1618  | 
|         |   1619 					attributeError = aElement.SetAttributeL(*attributeName, *attributeValue, iStoreInvalid); | 
|         |   1620 					if( attributeError != KErrNone && error == KErrNone) | 
|         |   1621 						{ | 
|         |   1622 						error = KErrXMLInvalidAttribute; | 
|         |   1623 						} | 
|         |   1624 					CleanupStack::PopAndDestroy(attributeValue); //attributeValue | 
|         |   1625 					} | 
|         |   1626 				else if(error == KErrNone) | 
|         |   1627 					{ | 
|         |   1628 					error = KErrXMLBadAttributeValue; | 
|         |   1629 					} | 
|         |   1630 				} | 
|         |   1631 			} | 
|         |   1632  | 
|         |   1633 		// next attribute pair | 
|         |   1634 		offset = aTagToParse.Find(KEqualSign); | 
|         |   1635 		CleanupStack::PopAndDestroy(attributeName); //attributeName | 
|         |   1636 		} | 
|         |   1637  | 
|         |   1638 	if(error == KErrNone && aTagToParse.Length() != 0) | 
|         |   1639 		{ | 
|         |   1640 		error = KErrXMLBadAttributeValue; | 
|         |   1641 		} | 
|         |   1642  | 
|         |   1643 	return error; | 
|         |   1644 	} | 
|         |   1645  | 
|         |   1646 TInt CMDXMLParser::LocateNextAttribute(const TDesC& aTagToParse) | 
|         |   1647 	{ | 
|         |   1648 	// Find the next attribute by looking for an = then search back for a ' '. | 
|         |   1649 	// This is useful when you've hit rubbish parsing the content of a start tag | 
|         |   1650 	// and are looking for somewhere sensible to start. | 
|         |   1651 	TInt nextAttribute = KErrNotFound; | 
|         |   1652 	TInt offset = aTagToParse.Find(KEqualSign); | 
|         |   1653  | 
|         |   1654 	// If the = is the first character then there isn't space for a ' ' so | 
|         |   1655 	// don't bother looking | 
|         |   1656 	if(offset > 0) | 
|         |   1657 		{ | 
|         |   1658 		TPtrC invalidText = aTagToParse.Left(offset); | 
|         |   1659 		nextAttribute = invalidText.LocateReverse(' '); | 
|         |   1660 		} | 
|         |   1661  | 
|         |   1662 	return nextAttribute; | 
|         |   1663 	} | 
|         |   1664  | 
|         |   1665 TInt CMDXMLParser::ParseElementEndTag(CMDXMLElement& aElement, const TDesC& aTagToParse) | 
|         |   1666 // | 
|         |   1667 // Parses an end tag.  In fact, at this point the end tag must match | 
|         |   1668 // the tag name of the start tag.   | 
|         |   1669 // @param aTagToParse Text of the end tag. | 
|         |   1670 // @return Returns KErrNone if the end tag matches the start tag or KErrNotFound if there is a mismatch. | 
|         |   1671 // | 
|         |   1672 	{ | 
|         |   1673 	// The tag should be of the form '</tag>' where tag is the name of this element so we will | 
|         |   1674 	// check and strip off the surrounding </  > and then compare the remains with this # | 
|         |   1675 	// node name. | 
|         |   1676 	TInt retVal = KErrNone; | 
|         |   1677 	if( aTagToParse.Length() != (aElement.NodeName().Length()+3)) | 
|         |   1678 		{ | 
|         |   1679 		retVal = KErrNotFound; | 
|         |   1680 		} | 
|         |   1681 	else | 
|         |   1682 		{ | 
|         |   1683 		TInt startEndTagLen = TPtrC(KXMLStartEndTag).Length(); | 
|         |   1684 		TInt endTagLen = TPtrC(KXMLEndTag).Length(); | 
|         |   1685  | 
|         |   1686 		if((aTagToParse.Left(startEndTagLen).Compare(KXMLStartEndTag) == 0) && | 
|         |   1687 				(aTagToParse.Right(endTagLen).Compare(KXMLEndTag) == 0)) | 
|         |   1688 			{ | 
|         |   1689 			if(aElement.NodeName().Compare(aTagToParse.Mid(2, | 
|         |   1690 						aTagToParse.Length() - (startEndTagLen + endTagLen))) != 0) | 
|         |   1691 				{ | 
|         |   1692 				retVal = KErrNotFound; | 
|         |   1693 				} | 
|         |   1694 			} | 
|         |   1695 		} | 
|         |   1696 	return retVal; | 
|         |   1697 	} | 
|         |   1698  | 
|         |   1699  | 
|         |   1700 //================================================================================== | 
|         |   1701  | 
|         |   1702 EXPORT_C void CMDXMLParser::SetError(const TInt aErrorCode, const TXMLErrorCodeSeverity aSeverity) | 
|         |   1703 // | 
|         |   1704 // Sets iError to new errorcode if more serious than any error so far encountered | 
|         |   1705 // | 
|         |   1706 	{ | 
|         |   1707 	if(iSeverity > aSeverity) | 
|         |   1708 		{ | 
|         |   1709 		iSeverity = aSeverity; | 
|         |   1710 		iError = aErrorCode; | 
|         |   1711 		} | 
|         |   1712 	} | 
|         |   1713  | 
|         |   1714 //================================================================================== | 
|         |   1715  | 
|         |   1716 EXPORT_C TInt CMDXMLParser::Error() const | 
|         |   1717 	{ | 
|         |   1718 	return iError; | 
|         |   1719 	} | 
|         |   1720  | 
|         |   1721 //================================================================================== | 
|         |   1722  | 
|         |   1723 EXPORT_C TXMLErrorCodeSeverity CMDXMLParser::ErrorSeverity() const | 
|         |   1724 	{ | 
|         |   1725 	return iSeverity; | 
|         |   1726 	} | 
|         |   1727  | 
|         |   1728 //================================================================================== | 
|         |   1729  | 
|         |   1730 void CMDXMLParser::HandleTextL(TDes& aChar) | 
|         |   1731 // | 
|         |   1732 // Called when a character is read in and found to bo outside of an element tag | 
|         |   1733 // | 
|         |   1734 	{ | 
|         |   1735 	// Save the text in a buffer. | 
|         |   1736 	// This text will get added as as a child element when the next tag is encounted. | 
|         |   1737 	if (iText == NULL) | 
|         |   1738 		iText = HBufC::NewL(KGMXMLDefaultTextBufferSize); | 
|         |   1739 	 | 
|         |   1740 	if (iText->Length() == iText->Des().MaxLength()) | 
|         |   1741 		// The buffer will overflow if we add another character. | 
|         |   1742 		// Need to reallocate. | 
|         |   1743 		{ | 
|         |   1744 		iText = iText->ReAllocL(iText->Des().MaxLength() + KGMXMLDefaultTextBufferSize); | 
|         |   1745 		} | 
|         |   1746  | 
|         |   1747 	iText->Des().Append(aChar); | 
|         |   1748 	} | 
|         |   1749  | 
|         |   1750 TBool CMDXMLParser::EndOfCDataSection() | 
|         |   1751 	{ | 
|         |   1752 	TBool endOfCData = EFalse; | 
|         |   1753 	TPtrC cdataEndSection(KXMLEndCDataSection); | 
|         |   1754 	TInt instLen = TPtrC(KXMLEndCDataSection).Length()-1; | 
|         |   1755  | 
|         |   1756 	__ASSERT_DEBUG(iElementTag != NULL, Panic(ENullMemVarElementTag)); | 
|         |   1757 	if(iElementTag->Right(instLen) == cdataEndSection.Left(instLen)) | 
|         |   1758 		{ | 
|         |   1759 		if(iElementTag->Left(instLen) == KXMLStartCDataSection) | 
|         |   1760 			endOfCData = ETrue; | 
|         |   1761 		} | 
|         |   1762  | 
|         |   1763 	return endOfCData; | 
|         |   1764 	} | 
|         |   1765  | 
|         |   1766 TInt CMDXMLParser::CheckForStartCData(const TDesC& aTextToCheck) | 
|         |   1767 	{ | 
|         |   1768 	TInt index; | 
|         |   1769 	index = aTextToCheck.Find(KXMLStartCDataSection); | 
|         |   1770 	return index; | 
|         |   1771 	} | 
|         |   1772  | 
|         |   1773 TInt CMDXMLParser::FindDelimiter(TDesC& aDataToSearch, TDesC& aDelimiterToFind) | 
|         |   1774 	{ | 
|         |   1775 	TInt currentOffset = 0; | 
|         |   1776 	TInt nextDelimiter = KErrNotFound; | 
|         |   1777 	TBool valid = EFalse; | 
|         |   1778 	TPtrC unsearchedData(aDataToSearch); | 
|         |   1779  | 
|         |   1780 	while (!valid && ((nextDelimiter = unsearchedData.Find(aDelimiterToFind)) != KErrNotFound)) | 
|         |   1781 		{ | 
|         |   1782 		// If this isn't the first time round the loop (When currentOffset == 0) we're moved | 
|         |   1783 		// our attention to the character after the delimiter we found, so add one to currentOffset | 
|         |   1784 		if(currentOffset != 0) | 
|         |   1785 			{ | 
|         |   1786 			currentOffset += 1; | 
|         |   1787 			} | 
|         |   1788 		// We have a delimiter, add the position of this to currentOffset | 
|         |   1789 		currentOffset += nextDelimiter; | 
|         |   1790  | 
|         |   1791 		// Check whether this delimiter is in a CDataSection, it's valid if it isn't | 
|         |   1792 		TPtrC delimiterToCheck = aDataToSearch.Left(currentOffset); | 
|         |   1793 		valid = !InCDataSection(delimiterToCheck); | 
|         |   1794  | 
|         |   1795 		// Move on to the next section of text in case this one wasn't valid | 
|         |   1796 		unsearchedData.Set(aDataToSearch.Mid(currentOffset + 1)); | 
|         |   1797 		} | 
|         |   1798  | 
|         |   1799 	if ((nextDelimiter == KErrNotFound) && (!valid)) | 
|         |   1800 		{ | 
|         |   1801 		return KErrNotFound; | 
|         |   1802 		} | 
|         |   1803 	else | 
|         |   1804 		{ | 
|         |   1805 		return currentOffset; | 
|         |   1806 		} | 
|         |   1807 	} | 
|         |   1808  | 
|         |   1809 void CMDXMLParser::AddTextL(CMDXMLElement* aParentElement) | 
|         |   1810 	{ | 
|         |   1811 	if ((aParentElement != NULL) && (iText != NULL)) | 
|         |   1812 	// Add any buffered text to the parent element unless it contains only whitespace | 
|         |   1813 		{ | 
|         |   1814 		// Strip off any leading whitespace | 
|         |   1815 		TInt stripCounter = 0; | 
|         |   1816 		 | 
|         |   1817 		if (!iPreserve) // GmXML consumes whitespace characters  | 
|         |   1818 			{ | 
|         |   1819 			TBool endOfWhitespace = EFalse; | 
|         |   1820 			while ((stripCounter < iText->Length()) && (!endOfWhitespace)) | 
|         |   1821 				{ | 
|         |   1822 				// If character is not 0x20 (space) and not between 0x09 and 0x0d  | 
|         |   1823 				// it isn't whitespace  | 
|         |   1824 				if( ((*iText)[stripCounter] != 0x20) && | 
|         |   1825 					!((*iText)[stripCounter] >= 0x09 && (*iText)[stripCounter] <= 0x0d)) | 
|         |   1826 					{ | 
|         |   1827 					endOfWhitespace = ETrue; | 
|         |   1828 					} | 
|         |   1829 				else | 
|         |   1830 					{ | 
|         |   1831 					stripCounter++; | 
|         |   1832 					} | 
|         |   1833 				} | 
|         |   1834 			} | 
|         |   1835  | 
|         |   1836 		HBufC* strippedText = TPtrC(iText->Right(iText->Length() - stripCounter)).AllocLC(); | 
|         |   1837  | 
|         |   1838 		if (strippedText->Length() > 0) | 
|         |   1839 			// If there is anything left of the stripped text then entity convert and add it. | 
|         |   1840 			{ | 
|         |   1841 			TPtr toConvert = strippedText->Des(); | 
|         |   1842 			TInt error = iEntityConverter->EntityToTextL(toConvert); | 
|         |   1843 			if( error != KErrNone ) | 
|         |   1844 				{ | 
|         |   1845 				SetError(error, EXMLIndeterminate); | 
|         |   1846 				} | 
|         |   1847 			CMDXMLText* textElement = CMDXMLText::NewLC(iXMLDoc); | 
|         |   1848 			textElement->SetDataL(*strippedText); | 
|         |   1849 			CleanupStack::Pop(textElement); | 
|         |   1850 			TInt err = aParentElement->AppendChild(textElement); | 
|         |   1851 			if(err != KErrNone) | 
|         |   1852 				{ | 
|         |   1853 				SetError(err, EXMLWorkable); | 
|         |   1854 				}			 | 
|         |   1855 			} | 
|         |   1856  | 
|         |   1857 		CleanupStack::PopAndDestroy(strippedText); | 
|         |   1858 		iText->Des().Zero(); | 
|         |   1859 		} | 
|         |   1860 	} | 
|         |   1861  | 
|         |   1862 TBool CMDXMLParser::InCDataSection(TDesC& aDataToSearch) | 
|         |   1863 	{ | 
|         |   1864 	TBool inCDataSection = EFalse; | 
|         |   1865 	TInt startCData = CheckForStartCData(aDataToSearch); | 
|         |   1866 	TInt endCData = 0; | 
|         |   1867  | 
|         |   1868 	while ((startCData != KErrNotFound) && !inCDataSection) | 
|         |   1869 		{ | 
|         |   1870 		// We only want to look for the end of the CDataSection in the part of | 
|         |   1871 		// aDataToSearch after the start of the CDataSection.  We know that the  | 
|         |   1872 		// first (TPtrC)KXMLStartCDataSection.Length() of the data we're looking | 
|         |   1873 		// at won't match because it's the start tag, but it's probably more  | 
|         |   1874 		// efficient to check the extra few characters than to work out the  | 
|         |   1875 		// length of the tag so we can ignore them. | 
|         |   1876 		startCData += endCData; | 
|         |   1877 		TPtrC afterStart = aDataToSearch.Mid(startCData); | 
|         |   1878 		endCData = afterStart.Find(KXMLEndCDataSection); | 
|         |   1879 		if (endCData == KErrNotFound) | 
|         |   1880 			{ | 
|         |   1881 			// We haven't found a match for the start of the CDataSection so | 
|         |   1882 			// we must still be in it -> "<" is valid. | 
|         |   1883 			inCDataSection = ETrue; | 
|         |   1884 			} | 
|         |   1885 		else  | 
|         |   1886 			{ | 
|         |   1887 			// We found a match for the start of the CDataSection.  Check to | 
|         |   1888 			// see if another one has started since then. | 
|         |   1889 			endCData += startCData; | 
|         |   1890 			TPtrC afterEnd = aDataToSearch.Mid(endCData); | 
|         |   1891 			startCData = CheckForStartCData(afterEnd); | 
|         |   1892 			} | 
|         |   1893 		} | 
|         |   1894  | 
|         |   1895 	return inCDataSection; | 
|         |   1896 	} | 
|         |   1897  | 
|         |   1898 TInt CMDXMLParser::ParseSingleAttributeL(TDes& aAttributeValue) | 
|         |   1899 	{ | 
|         |   1900 	TInt error = KErrNone; | 
|         |   1901 	TInt beginSection = 0; | 
|         |   1902 	TInt endSection = aAttributeValue.Find(KXMLStartCDataSection); | 
|         |   1903 	 | 
|         |   1904 	// We've found at least one CDataSection | 
|         |   1905 	while(endSection != KErrNotFound) | 
|         |   1906 		{ | 
|         |   1907 		// Entity convert this plain text section | 
|         |   1908 		HBufC* textToConvert = TPtrC(aAttributeValue.Mid(beginSection, endSection)).AllocLC(); | 
|         |   1909 		TPtr toConvert = textToConvert->Des(); | 
|         |   1910 		error = iEntityConverter->EntityToTextL(toConvert); | 
|         |   1911 		aAttributeValue.Replace(beginSection, endSection, *textToConvert); | 
|         |   1912 		CleanupStack::PopAndDestroy(textToConvert); | 
|         |   1913  | 
|         |   1914 		// Move on our markers.  We start the new section at the end of the old one. | 
|         |   1915 		beginSection += endSection; | 
|         |   1916 		// The end of this new section is the end of the CDataSection | 
|         |   1917 		endSection = TPtrC(aAttributeValue.Mid(beginSection)).Find(KXMLEndCDataSection); | 
|         |   1918  | 
|         |   1919 		if(endSection != KErrNotFound) | 
|         |   1920 			{ | 
|         |   1921 			// Now move on our markers again.  Start at the end of the CDataSection,  | 
|         |   1922 			// plus the length of the end tag, and continue to the beginning of the next one. | 
|         |   1923 			beginSection += endSection + TPtrC(KXMLEndCDataSection).Length(); | 
|         |   1924 			endSection = TPtrC(aAttributeValue.Mid(beginSection)).Find(KXMLStartCDataSection); | 
|         |   1925 			} | 
|         |   1926 		else | 
|         |   1927 			{ | 
|         |   1928 			// There's an unterminated CDataSection in our attribute | 
|         |   1929 			error = KErrXMLBadAttributeValue; | 
|         |   1930 			} | 
|         |   1931 		} | 
|         |   1932  | 
|         |   1933 	// There are no more CDataSections, entity convert the rest of the string | 
|         |   1934 	if(!error) | 
|         |   1935 		{ | 
|         |   1936 		HBufC* textToConvert = TPtrC(aAttributeValue.Mid(beginSection)).AllocLC(); | 
|         |   1937 		TPtr toConvert = textToConvert->Des(); | 
|         |   1938 		error = iEntityConverter->EntityToTextL(toConvert); | 
|         |   1939 		aAttributeValue.Replace(beginSection, (aAttributeValue.Length()-beginSection), *textToConvert); | 
|         |   1940 		CleanupStack::PopAndDestroy(textToConvert); | 
|         |   1941 		} | 
|         |   1942  | 
|         |   1943 	return error; | 
|         |   1944 	} | 
|         |   1945  | 
|         |   1946  | 
|         |   1947 EXPORT_C void CMDXMLParser::PlaceholderForRemovedExport1(MMDXMLParserObserver* /*aParserObserver*/) | 
|         |   1948 	{ | 
|         |   1949 	User::Panic(KLDRIMPORT, KLdrImportedOrdinalDoesNotExist); | 
|         |   1950 	} | 
|         |   1951  | 
|         |   1952 EXPORT_C void CMDXMLParser::PlaceholderForRemovedExport2(MMDXMLParserObserver* /*aParserObserver*/, MXMLDtd* /*aDtdRepresentation*/) | 
|         |   1953 	{ | 
|         |   1954 	User::Panic(KLDRIMPORT, KLdrImportedOrdinalDoesNotExist); | 
|         |   1955 	} | 
|         |   1956  | 
|         |   1957 EXPORT_C void CMDXMLParser::PlaceholderForRemovedExport3() | 
|         |   1958 	{ | 
|         |   1959 	User::Panic(KLDRIMPORT, KLdrImportedOrdinalDoesNotExist); | 
|         |   1960 	} | 
|         |   1961  | 
|         |   1962 // End of File |