xml/legacyminidomparser/XMLParser/SRC/GMXMLComposer.cpp
changeset 34 c7e9f1c97567
parent 25 417699dc19c9
child 36 172b09aa4eb6
equal deleted inserted replaced
25:417699dc19c9 34:c7e9f1c97567
     1 // Copyright (c) 2004-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 // GMXMLCOMPOSE.CPP
       
    15 // @file
       
    16 // This file contains the declaration of the generic CMDXMLComposer class 
       
    17 // which is responsible for creating an XML file
       
    18 // from a given DOM structure.
       
    19 // 
       
    20 //
       
    21 
       
    22 #include <f32file.h>
       
    23 #include <utf.h>
       
    24 
       
    25 #include <gmxmlconstants.h>
       
    26 #include <gmxmlnode.h>
       
    27 #include <gmxmldocument.h>
       
    28 #include <gmxmlelement.h>
       
    29 #include <gmxmlcomposer.h>
       
    30 #include <gmxmlentityconverter.h>
       
    31 #include <gmxmltext.h>
       
    32 #include <gmxmlprocessinginstruction.h>
       
    33 #include <gmxmlcomment.h>
       
    34 #include <gmxmlcdatasection.h>
       
    35 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS 
       
    36 #include "gmxmldummydtd.h"
       
    37 #endif
       
    38 
       
    39 _LIT(KXmlQuotation, "&quot;");
       
    40 
       
    41 //
       
    42 // CMDXMLComposer					//
       
    43 //
       
    44 
       
    45 CMDXMLComposer::CMDXMLComposer(MMDXMLComposerObserver* aComposerObserver) : CActive(EPriorityNormal)
       
    46 //
       
    47 // Constructor
       
    48 //
       
    49 	{
       
    50 	iComposerObserver = aComposerObserver;
       
    51 	iOutputProlog = ETrue;
       
    52 	CActiveScheduler::Add(this);
       
    53 	}
       
    54 	
       
    55 CMDXMLComposer::CMDXMLComposer(MMDXMLComposerObserver* aComposerObserver, TBool aOutputProlog) : CActive(EPriorityNormal),
       
    56 	iOutputProlog(aOutputProlog)
       
    57 //
       
    58 // Constructor
       
    59 //
       
    60 	{
       
    61 	iComposerObserver = aComposerObserver;
       
    62 	CActiveScheduler::Add(this);
       
    63 	}
       
    64 //==================================================================================
       
    65 
       
    66 EXPORT_C CMDXMLComposer::~CMDXMLComposer()
       
    67 	{
       
    68 	Cancel();
       
    69 	delete iEntityConverter;
       
    70 	delete iCharconv;
       
    71 
       
    72 	iXMLFile.Close();
       
    73 	}
       
    74 
       
    75 //==================================================================================
       
    76 
       
    77 void CMDXMLComposer::BaseConstructL()
       
    78 	{
       
    79 	iCharconv = CCnvCharacterSetConverter::NewL();
       
    80 	iCharconv->SetDowngradeForExoticLineTerminatingCharacters(
       
    81 		CCnvCharacterSetConverter::EDowngradeExoticLineTerminatingCharactersToJustLineFeed);
       
    82 	}
       
    83 
       
    84 //==================================================================================
       
    85 
       
    86 EXPORT_C CMDXMLComposer* CMDXMLComposer::NewL(MMDXMLComposerObserver* aComposerObserver)
       
    87 //
       
    88 // Two phase static factory function constructor
       
    89 // @param aEntityStrings the string table which lists the entity references and conversion
       
    90 // @return Created CMDXMLComposer
       
    91 // @leave can Leave due to OOM
       
    92 //
       
    93 	{
       
    94 	CMDXMLComposer* self = NewLC(aComposerObserver);
       
    95 	CleanupStack::Pop(self);
       
    96 	return self;
       
    97 	}
       
    98 	
       
    99 //==================================================================================
       
   100 
       
   101 EXPORT_C CMDXMLComposer* CMDXMLComposer::NewL(MMDXMLComposerObserver* aComposerObserver, TBool aOutputProlog)
       
   102 //
       
   103 // Two phase static factory function constructor
       
   104 // @param aEntityStrings the string table which lists the entity references and conversion
       
   105 // @param aOutputProlog Whether the Doctype and Version tags should be output.  This is
       
   106 // provided for MMS conformance.
       
   107 // @return Created CMDXMLComposer
       
   108 // @leave can Leave due to OOM
       
   109 //
       
   110 	{
       
   111 	CMDXMLComposer* self = NewLC(aComposerObserver, aOutputProlog);
       
   112 	CleanupStack::Pop(self);
       
   113 	return self;
       
   114 	}
       
   115 	
       
   116 //==================================================================================
       
   117 
       
   118 EXPORT_C CMDXMLComposer* CMDXMLComposer::NewLC(MMDXMLComposerObserver* aComposerObserver)
       
   119 //
       
   120 // Two phase static factory function constructor
       
   121 // @param aEntityStrings the string table which lists the entity references and conversion
       
   122 // @return Created CMDXMLComposer
       
   123 // @leave can Leave due to OOM
       
   124 //
       
   125 	{
       
   126 	CMDXMLComposer* self = new (ELeave) CMDXMLComposer(aComposerObserver);
       
   127 	CleanupStack::PushL(self);
       
   128 	self->ConstructL();
       
   129 	return self;
       
   130 	}
       
   131 	
       
   132 //==================================================================================
       
   133 
       
   134 EXPORT_C CMDXMLComposer* CMDXMLComposer::NewLC(MMDXMLComposerObserver* aComposerObserver, TBool aOutputProlog)
       
   135 //
       
   136 // Two phase static factory function constructor
       
   137 // @param aEntityStrings the string table which lists the entity references and conversion
       
   138 // @param aOutputProlog Whether the Doctype and Version tags should be output.  This is
       
   139 // provided for MMS conformance.
       
   140 // @return Created CMDXMLComposer
       
   141 // @leave can Leave due to OOM
       
   142 //
       
   143 	{
       
   144 	CMDXMLComposer* self = new (ELeave) CMDXMLComposer(aComposerObserver, aOutputProlog);
       
   145 	CleanupStack::PushL(self);
       
   146 	self->ConstructL();
       
   147 	return self;
       
   148 	}
       
   149 	
       
   150 //==================================================================================
       
   151 
       
   152 void CMDXMLComposer::ConstructL()
       
   153 //
       
   154 // Second stage constructor
       
   155 // @param aEntityStrings the string table which lists the entity references and conversion
       
   156 //
       
   157 	{
       
   158 	BaseConstructL();
       
   159 	CMDXMLEntityConverter* entityConverter = new(ELeave) CMDXMLEntityConverter();
       
   160 	SetEntityConverter(entityConverter);
       
   161 	}
       
   162 
       
   163 
       
   164 //==================================================================================
       
   165 
       
   166 void CMDXMLComposer::InitialiseCompose(CMDXMLDocument* aDocument, TXMLFileType aFileType)
       
   167 	{
       
   168 	Cancel();
       
   169 	
       
   170 	iError = KErrNone;
       
   171 	iSeverity = EXMLNone;
       
   172 	iOutputBuffer.Zero();
       
   173 
       
   174 	iXMLDoc = aDocument;
       
   175 	iFileType = aFileType;
       
   176 
       
   177 	iOnlyCalculatingSize = EFalse;
       
   178 	iSizeTally = 0;
       
   179 	}
       
   180 
       
   181 EXPORT_C TInt CMDXMLComposer::ComposeFile(RFs aRFs, const TDesC& aFileToCompose, CMDXMLDocument* aDocument, TXMLFileType aFileType)
       
   182 /** Starts file composition.
       
   183 
       
   184 This function can not be called if there is an outstanding size calculation or compose
       
   185 operation in progress. If it is necessary to run two asynchronous operations in parallel
       
   186 then two instances of the CMDXMLComposer are needed.
       
   187 
       
   188 @param aRFS File system to use
       
   189 @param aFileToCompose Name of file to create
       
   190 @param aDocument The document object to compose to the file
       
   191 @return KERRNone if successful
       
   192 **/
       
   193 	{
       
   194 	InitialiseCompose(aDocument, aFileType);
       
   195 	iRFs = aRFs;
       
   196 	TInt error = KErrNone;
       
   197 
       
   198 	if(iXMLDoc == NULL)
       
   199 		{
       
   200 		error = KErrNotSupported;
       
   201 		}
       
   202 	else
       
   203 		{
       
   204 		switch(iFileType)
       
   205 			{
       
   206 			case EAscii:
       
   207 				{
       
   208 				error = iXMLFile.Replace(aRFs, aFileToCompose, EFileWrite | EFileStream);
       
   209 				break;
       
   210 				}
       
   211 			case EUnicode:
       
   212 				error = iXMLFile.Replace(aRFs, aFileToCompose, EFileWrite | EFileStream);
       
   213 				if(error == KErrNone)
       
   214 					{
       
   215 					// append Unicode File identifier to start of output text
       
   216 					iOutputBuffer.Append(CEditableText::EByteOrderMark);
       
   217 					}
       
   218 				break;
       
   219 			case EUtf8:
       
   220 				{
       
   221 				error = iXMLFile.Replace(aRFs, aFileToCompose, EFileWrite | EFileStream);
       
   222 				break;
       
   223 				}
       
   224 			default:
       
   225 				error = KErrNotSupported;
       
   226 				break;
       
   227 			}
       
   228 		}
       
   229 
       
   230 	if(error == KErrNone)
       
   231 		{
       
   232 		SetActive();
       
   233 		TRequestStatus* s=&iStatus;
       
   234 		User::RequestComplete(s, KErrNone);
       
   235 		}
       
   236 	else
       
   237 		{
       
   238 		SetError(error, EXMLFatal);
       
   239 		}
       
   240 
       
   241 	return error;
       
   242 	}
       
   243 	
       
   244 /** Starts file composition to an open file handle.
       
   245 
       
   246 This function must not be called when file sizing is in progress. If it is necessary to calulate
       
   247 the size and generate the XML simultaneously then two instances of the composer should be used,
       
   248 one for sizing and one for composition.
       
   249 
       
   250 @param aFileHandleToCompose An open file handle to write to. Ownership of the file handle is passed even if an error occurs.
       
   251 @param aDocument The document object to compose to the file.
       
   252 @param aFileType Type of the output file.
       
   253 @return KErrNone if successful.
       
   254 */
       
   255 EXPORT_C TInt CMDXMLComposer::ComposeFile(RFile& aFileHandleToCompose, CMDXMLDocument* aDocument, TXMLFileType aFileType)
       
   256 	{
       
   257 	InitialiseCompose(aDocument, aFileType);
       
   258 	iXMLFile = aFileHandleToCompose;
       
   259 	TInt error = KErrNone;
       
   260 
       
   261 	if(iXMLDoc == NULL)
       
   262 		{
       
   263 		error = KErrNotSupported;
       
   264 		}
       
   265 	else
       
   266 		{
       
   267 		switch(iFileType)
       
   268 			{
       
   269 			case EUnicode:
       
   270 				{
       
   271 				// append Unicode File identifier to start of output text
       
   272 				iOutputBuffer.Append(CEditableText::EByteOrderMark);
       
   273 				}
       
   274 			case EAscii:
       
   275 			case EUtf8:
       
   276 				break;
       
   277 			
       
   278 			default:
       
   279 				error = KErrNotSupported;
       
   280 				break;
       
   281 			}
       
   282 		}
       
   283 	
       
   284 	if(error == KErrNone)
       
   285 		{
       
   286 		iStatus = KRequestPending;
       
   287 		SetActive();
       
   288 		TRequestStatus* s=&iStatus;
       
   289 		User::RequestComplete(s, KErrNone);
       
   290 		}
       
   291 	else
       
   292 		{
       
   293 		iXMLFile.Close();
       
   294 		SetError(error, EXMLFatal);
       
   295 		}
       
   296 
       
   297 	return error;
       
   298 	}
       
   299 
       
   300 //==================================================================================
       
   301 
       
   302 /** Starts calculating the size of the XML output without actually writing it to the file.
       
   303 
       
   304 This process is asyncronous, the size value is only updated when ComposeFileComplete
       
   305 is called on the MMDXMLComposerObserver passed in in the NewL.
       
   306 
       
   307 This function can not be called if there is an outstanding size calculation or compose
       
   308 operation in progress. If it is necessary to run two asynchronous operations in parallel
       
   309 then two instances of CMDXMLComposer are needed.
       
   310 
       
   311 @param aSize Will be set to the size of the XML document when composition has completed.
       
   312 @param aDocument The document object to size
       
   313 @param aFileType Type of the output file, required because it will affect the size of the XML
       
   314 @return KErrNone if successful */
       
   315 
       
   316 EXPORT_C TInt CMDXMLComposer::CalculateFileSize(TInt& aSize, CMDXMLDocument* aDocument, TXMLFileType aFileType)
       
   317 	{
       
   318 	Cancel();
       
   319 	
       
   320 	iError = KErrNone;
       
   321 	iSeverity = EXMLNone;
       
   322 	iOutputBuffer.Zero();
       
   323 
       
   324 	iXMLDoc = aDocument;
       
   325 	iFileType = aFileType;
       
   326 	TInt error = KErrNone;
       
   327 
       
   328 	if (iFileType == EUnicode)
       
   329 		{
       
   330 		// The size tally must be incremented by two characters because the unicode byte marker
       
   331 		// gets added in the ComposeFile function that does not get called when we are calculating
       
   332 		// the size.
       
   333 		iSizeTally = 2;
       
   334 		}
       
   335 	else
       
   336 		{
       
   337 		iSizeTally = 0;
       
   338 		}
       
   339 
       
   340 	iSize = &aSize;
       
   341 	iOnlyCalculatingSize = ETrue;
       
   342 
       
   343 	if(iXMLDoc == NULL)
       
   344 		{
       
   345 		error = KErrNotSupported;
       
   346 		}
       
   347 
       
   348 	if(error == KErrNone)
       
   349 		{
       
   350 		SetActive();
       
   351 		TRequestStatus* s=&iStatus;
       
   352 		User::RequestComplete(s, KErrNone);
       
   353 		}
       
   354 	else
       
   355 		{
       
   356 		SetError(error, EXMLFatal);
       
   357 		}
       
   358 
       
   359 	return error;
       
   360 	}
       
   361 
       
   362 //==================================================================================
       
   363 
       
   364 EXPORT_C TInt CMDXMLComposer::Error() const
       
   365 	{
       
   366 	return iError;
       
   367 	}
       
   368 
       
   369 //==================================================================================
       
   370 
       
   371 EXPORT_C TXMLErrorCodeSeverity CMDXMLComposer::ErrorSeverity() const
       
   372 	{
       
   373 	return iSeverity;
       
   374 	}
       
   375 
       
   376 //==================================================================================
       
   377 	
       
   378 EXPORT_C CMDXMLEntityConverter* CMDXMLComposer::EntityConverter() const
       
   379 	{
       
   380 	return iEntityConverter;
       
   381 	}
       
   382 
       
   383 //==================================================================================
       
   384 
       
   385 TInt CMDXMLComposer::OutputCommentL(const TDesC& aComment)
       
   386 //
       
   387 // Output a comment
       
   388 // @param aComment the comment text to output
       
   389 // @return KERRNone if successful, otherwise a file writing error.
       
   390 //
       
   391 	{
       
   392 	TInt error = KErrNone;
       
   393 
       
   394 	if(iSeverity != EXMLFatal)
       
   395 		{
       
   396 		error = WriteFileL(KNewLine);
       
   397 		}
       
   398 
       
   399 #ifdef _DEBUG
       
   400 	for(TInt loopIndex = 0; loopIndex < iIndentationLevel; loopIndex++)
       
   401 		{
       
   402 		if(iSeverity != EXMLFatal)
       
   403 			{
       
   404 			error = WriteFileL(KTab);
       
   405 			}
       
   406 		}
       
   407 #endif
       
   408 
       
   409 	if(iSeverity != EXMLFatal)
       
   410 		{
       
   411 		error = WriteFileL(KXMLStartComment);
       
   412 		}
       
   413 
       
   414 	if(iSeverity != EXMLFatal)
       
   415 		{
       
   416 		error = WriteFileL(aComment);
       
   417 		}
       
   418 
       
   419 	if(iSeverity != EXMLFatal)
       
   420 		{
       
   421 		error = WriteFileL(KXMLEndComment);
       
   422 		}
       
   423 
       
   424 	return error;
       
   425 	}
       
   426 
       
   427 //==================================================================================
       
   428 
       
   429 TInt CMDXMLComposer::OutputProcessingInstructionL(const TDesC& aInstruction)
       
   430 //
       
   431 // Output a Processing Instruction
       
   432 // @param aInstruction the Processing Instruction text to output
       
   433 // @return KERRNone if successful, otherwise a file writing error.
       
   434 //
       
   435 	{
       
   436 	TInt error = KErrNone;
       
   437 
       
   438 	if(iSeverity != EXMLFatal)
       
   439 		{
       
   440 		error = WriteFileL(KNewLine);
       
   441 		}
       
   442 
       
   443 #ifdef _DEBUG
       
   444 	for(TInt loopIndex = 0; loopIndex < iIndentationLevel; loopIndex++)
       
   445 		{
       
   446 		if(iSeverity != EXMLFatal)
       
   447 			{
       
   448 			error = WriteFileL(KTab);
       
   449 			}
       
   450 		}
       
   451 #endif
       
   452 
       
   453 	if(iSeverity != EXMLFatal)
       
   454 		{
       
   455 		error = WriteFileL(KXMLStartProcessingInstruction);
       
   456 		}
       
   457 
       
   458 	if(iSeverity != EXMLFatal)
       
   459 		{
       
   460 		error = WriteFileL(aInstruction);
       
   461 		}
       
   462 
       
   463 	if(iSeverity != EXMLFatal)
       
   464 		{
       
   465 		error = WriteFileL(KXMLEndProcessingInstruction);
       
   466 		}
       
   467 
       
   468 	return error;
       
   469 	}
       
   470 
       
   471 
       
   472 //==================================================================================
       
   473 
       
   474 TInt CMDXMLComposer::OutputCDataSectionL(const TDesC& aCDataSection)
       
   475 //
       
   476 // Output a CDataSection
       
   477 // @param aCDataSection the data section text to output
       
   478 // @return KERRNone if successful, otherwise a file writing error.
       
   479 //
       
   480 	{
       
   481 	TInt error = KErrNone;
       
   482 	
       
   483 #ifdef _DEBUG
       
   484 	for(TInt loopIndex = 0; loopIndex < iIndentationLevel; loopIndex++)
       
   485 		{
       
   486 		if(iSeverity != EXMLFatal)
       
   487 			{
       
   488 			error = WriteFileL(KTab);
       
   489 			}
       
   490 		}
       
   491 #endif
       
   492 
       
   493 	if(iSeverity != EXMLFatal)
       
   494 		{
       
   495 		error = WriteFileL(KXMLStartCDataSection);
       
   496 		}
       
   497 
       
   498 	if(iSeverity != EXMLFatal)
       
   499 		{
       
   500 		error = WriteFileL(aCDataSection);
       
   501 		}
       
   502 
       
   503 	if(iSeverity != EXMLFatal)
       
   504 		{
       
   505 		error = WriteFileL(KXMLEndCDataSection);
       
   506 		}
       
   507 
       
   508 	return error;
       
   509 	}
       
   510 
       
   511 //==================================================================================
       
   512 //Defect fix for INC036136- Enable the use of custom entity converters in GMXML
       
   513 
       
   514 EXPORT_C TInt CMDXMLComposer::OutputDataL(const TDesC& aData)
       
   515 //
       
   516 // Output raw data
       
   517 // it's only intended to be used from within a custom entity converter as
       
   518 // it relies on a Composer sesssion already being in progress
       
   519 // @param the data to be output
       
   520 // @return KERRNone if successful, otherwise a file writing error.
       
   521 //
       
   522 	{
       
   523 	TInt error = KErrNone;
       
   524 
       
   525 	if(iSeverity != EXMLFatal)
       
   526 		{
       
   527 		if(aData.Find(KQuotation) != KErrNotFound)
       
   528 			{
       
   529 			error = ReplaceXmlCharactersL(aData, KQuotation);
       
   530 			}
       
   531 		else
       
   532 			{
       
   533 			error = WriteFileL(aData);	
       
   534 			}		
       
   535 		}
       
   536 
       
   537 	return error;
       
   538 	}
       
   539 
       
   540 //==================================================================================
       
   541 /* Before writing to xml file, search for special character like quotation (").
       
   542    if it exist then replace it with &quot; and then write it to xml file.
       
   543    Refer section 5 of below URL for more information.
       
   544    http://www.xmlnews.org/docs/xml-basics.html
       
   545    @param aXmlData the data to be output
       
   546    @param aString the special character to search in aXmlData
       
   547    @return KERRNone if successful, otherwise a file writing error.	*/
       
   548    
       
   549 TInt CMDXMLComposer::ReplaceXmlCharactersL(const TDesC16& aXmlData, const TDesC& aString)
       
   550 	{
       
   551 	TInt xmlDataIndex;
       
   552 	const TDesC& quot = KXmlQuotation;
       
   553 	HBufC16* xmlData = aXmlData.AllocL();
       
   554 				
       
   555 	while((xmlDataIndex = (xmlData->Des()).Find(aString)) != KErrNotFound)
       
   556 		{
       
   557 		HBufC16* temp = HBufC::NewLC(((xmlData->Des()).Length() - 1) + quot.Length());
       
   558 		TPtr16 tempPtr = temp->Des();
       
   559 		tempPtr.Append((xmlData->Des()).Left(xmlDataIndex));
       
   560 		tempPtr.Append(quot);
       
   561 		tempPtr.Append((xmlData->Des()).Right((xmlData->Des()).Length() - (xmlDataIndex + 1)));
       
   562 		delete xmlData;
       
   563 		xmlData = NULL;
       
   564 		xmlData = tempPtr.AllocL();
       
   565 		CleanupStack::PopAndDestroy();	// temp
       
   566 		}
       
   567 	TInt error = WriteFileL((xmlData->Des()));
       
   568 	delete xmlData;
       
   569 	xmlData = NULL;
       
   570 	return error;
       
   571 	}
       
   572 
       
   573 //==================================================================================
       
   574 
       
   575 EXPORT_C void CMDXMLComposer::SetEntityConverter(CMDXMLEntityConverter* aEntityConverter)
       
   576 /*
       
   577 	 * Sets the entity converter to be used
       
   578 	 * and  take ownership of the passed entity converter
       
   579 	 * @param aEntityConverter The entity converter to be used
       
   580 	 */
       
   581 	{
       
   582 	delete iEntityConverter;
       
   583 	iEntityConverter = aEntityConverter;
       
   584 	}
       
   585 
       
   586 //End Defect fix for INC036136
       
   587 //==================================================================================
       
   588 
       
   589 EXPORT_C TInt CMDXMLComposer::OutputStartOfElementTagL(const TDesC& aElementName)
       
   590 //
       
   591 // Output a start of element tag
       
   592 // @param aElementName the name of the tag to output
       
   593 // @return KERRNone if successful, otherwise a file writing error.
       
   594 //
       
   595 	{
       
   596 	TInt error = KErrNone;
       
   597 
       
   598 #ifdef _DEBUG
       
   599 	for(TInt loopIndex = 0; loopIndex < iIndentationLevel; loopIndex++)
       
   600 		{
       
   601 		if(iSeverity != EXMLFatal)
       
   602 			{
       
   603 			error = WriteFileL(KTab);
       
   604 			}
       
   605 		}
       
   606 	iIndentationLevel++;
       
   607 #endif
       
   608 
       
   609 	if(iSeverity != EXMLFatal)
       
   610 		{
       
   611 		error = WriteFileL(KXMLStartTag);
       
   612 		}
       
   613 
       
   614 	if(iSeverity != EXMLFatal)
       
   615 		{
       
   616 		error = WriteFileL(aElementName);
       
   617 		}
       
   618 
       
   619 	return error;
       
   620 	}
       
   621 
       
   622 //==================================================================================
       
   623 
       
   624 EXPORT_C TInt CMDXMLComposer::OutputEndOfElementTagL(const TBool aHasChildren)
       
   625 //
       
   626 // Output an end of element start tag
       
   627 // @param aHasChildren true if the element has children
       
   628 // @return KERRNone if successful, otherwise a file writing error.
       
   629 //
       
   630 	{
       
   631 	TInt error = KErrNone;
       
   632 
       
   633 	if(iSeverity != EXMLFatal)
       
   634 		{
       
   635 		if(aHasChildren)
       
   636 			{
       
   637 			error = WriteFileL(KXMLEndTag);
       
   638 			}
       
   639 		else
       
   640 			{
       
   641 			error = WriteFileL(KXMLEndStartTag);
       
   642 
       
   643 	#ifdef _DEBUG
       
   644 			iIndentationLevel--;
       
   645 	#endif
       
   646 			}
       
   647 		}
       
   648 
       
   649 	return error;
       
   650 	}
       
   651 
       
   652 //==================================================================================
       
   653 
       
   654 TInt CMDXMLComposer::OutputEndTagL(const TDesC& aElementName)
       
   655 //
       
   656 // Output an end of element tag
       
   657 // @param aElementName the name of the tag to output
       
   658 // @return KERRNone if successful, otherwise a file writing error.
       
   659 //
       
   660 	{
       
   661 	TInt error = KErrNone;
       
   662 
       
   663 #ifdef _DEBUG
       
   664 	iIndentationLevel--;
       
   665 	for(TInt loopIndex = 0; loopIndex < iIndentationLevel; loopIndex++)
       
   666 		{
       
   667 		if(iSeverity != EXMLFatal)
       
   668 			{
       
   669 			error = WriteFileL(KTab);
       
   670 			}
       
   671 		}
       
   672 #endif
       
   673 	
       
   674 	if(iSeverity != EXMLFatal)
       
   675 		{
       
   676 		error = WriteFileL(KXMLStartEndTag);
       
   677 		}
       
   678 
       
   679 	if(iSeverity != EXMLFatal)
       
   680 		{
       
   681 		error = WriteFileL(aElementName);
       
   682 		}
       
   683 
       
   684 	if(iSeverity != EXMLFatal)
       
   685 		{
       
   686 		error = WriteFileL(KXMLEndTag);
       
   687 		}
       
   688 
       
   689 	return error;
       
   690 	}
       
   691 
       
   692 
       
   693 
       
   694 
       
   695 
       
   696 //==================================================================================
       
   697 
       
   698 EXPORT_C TInt CMDXMLComposer::OutputAttributeL(const TDesC& aAttributeName, const TDesC& aAttributeValue)
       
   699 //
       
   700 // Output an attribute - name and value.
       
   701 // @param aAttributeName the name of the attribute to output
       
   702 // @param aAttributeValue the text of the attribute value to output
       
   703 // @return KERRNone if successful, otherwise a file writing error.
       
   704 //
       
   705 	{
       
   706 	TInt error = KErrNone;
       
   707 
       
   708 	if(iSeverity != EXMLFatal)
       
   709 		{
       
   710 		error = WriteFileL(KSingleSpace);
       
   711 		}
       
   712 
       
   713 	if(iSeverity != EXMLFatal)
       
   714 		{
       
   715 		error = WriteFileL(aAttributeName);
       
   716 		}
       
   717 
       
   718 	if(iSeverity != EXMLFatal)
       
   719 		{
       
   720 		error = WriteFileL(KEqualSign);
       
   721 		}
       
   722 
       
   723 	if(iSeverity != EXMLFatal)
       
   724 		{
       
   725 		error = WriteFileL(KQuotation);
       
   726 		}
       
   727 
       
   728 	if(iSeverity != EXMLFatal)
       
   729 		{
       
   730 		// Work along the attribute value in sections.  We have two markers in the attribute,
       
   731 		// one at the beginning of the section we're working on and one at the end.  Initially
       
   732 		// beginSection is the start of the string, 0, the end of the section is the first
       
   733 		// CDataSection we find.
       
   734 		// beginSection is an offset within the string, endSection is an offset from that
       
   735 		TInt beginSection = 0;
       
   736 		TInt endSection = aAttributeValue.Find(KXMLStartCDataSection);
       
   737 		
       
   738 		// We've found at least one CDataSection
       
   739 		while(endSection != KErrNotFound)
       
   740 			{
       
   741 			// Entity convert this plain text section
       
   742 			TPtrC plainText = aAttributeValue.Mid(beginSection, endSection);
       
   743 			error = iEntityConverter->OutputComposedTextL(this, plainText);
       
   744 
       
   745 			// Move on our markers.  We start the new section at the end of the old one.
       
   746 			beginSection += endSection;
       
   747 			// The end of this section is the end of the CDataSection
       
   748 			endSection = TPtrC(aAttributeValue.Mid(beginSection)).Find(KXMLEndCDataSection);
       
   749 			if(endSection != KErrNotFound)
       
   750 				{
       
   751 				// The CDataSection ends at the beginning of the end tag, so we need to add
       
   752 				// on the length of the end tag before outputting it without conversion
       
   753 				endSection += TPtrC(KXMLEndCDataSection).Length();
       
   754 				OutputDataL(aAttributeValue.Mid(beginSection, endSection));
       
   755 
       
   756 				// Now move on our markers again.  Start at the end of the CDataSection, and
       
   757 				// continue to the beginning of the next one.
       
   758 				beginSection += endSection;
       
   759 				endSection = TPtrC(aAttributeValue.Mid(beginSection)).Find(KXMLStartCDataSection);
       
   760 				}
       
   761 			else
       
   762 				{
       
   763 				// There's an unterminated CDataSection in our attribute
       
   764 				error = KErrXMLBadAttributeValue;
       
   765 				}
       
   766 			}
       
   767 
       
   768 		// There are no more CDataSections, entity convert the rest of the string
       
   769 		if(!error)
       
   770 			{
       
   771 			error = iEntityConverter->OutputComposedTextL(this, aAttributeValue.Mid(beginSection));
       
   772 			}
       
   773 		}
       
   774 	
       
   775 	if(iSeverity != EXMLFatal)
       
   776 		{
       
   777 		error = WriteFileL(KQuotation);
       
   778 		}
       
   779 
       
   780 	return error;
       
   781 	}
       
   782 
       
   783 //==================================================================================
       
   784 
       
   785 EXPORT_C TInt CMDXMLComposer::RunError(TInt aError)
       
   786 //
       
   787 // RunError function inherited from CActive base class - intercepts any Leave from
       
   788 // the RunL() function, sets an appropriate errorcode and calls ComposeFileCompleteL
       
   789 //
       
   790 	{
       
   791 	iSeverity = EXMLFatal;
       
   792 	iError = aError;
       
   793 	iXMLFile.Close();
       
   794 	TRAPD(err, iComposerObserver->ComposeFileCompleteL());
       
   795 	return err;
       
   796 	}
       
   797 
       
   798 //==================================================================================
       
   799 
       
   800 EXPORT_C void CMDXMLComposer::DoCancel()
       
   801 //
       
   802 // DoCancel function inherited from CActive base class
       
   803 //
       
   804 	{
       
   805 	iXMLFile.Close();
       
   806 	}
       
   807 
       
   808 //==================================================================================
       
   809 
       
   810 void CMDXMLComposer::RunL()
       
   811 //
       
   812 // RunL function inherited from CActive base class - does the actual composition
       
   813 // @leave can Leave due to OOM
       
   814 //
       
   815 	{
       
   816 	// If this is an ASCII file then check that we can load the character set converter
       
   817 	if(iSeverity != EXMLFatal)
       
   818 		{
       
   819 		if(iFileType == EAscii)
       
   820 			{
       
   821 			if (iCharconv->PrepareToConvertToOrFromL(KCharacterSetIdentifierAscii, iRFs)!=
       
   822 				CCnvCharacterSetConverter::EAvailable)
       
   823 				{
       
   824 				SetError( KErrNotSupported, EXMLFatal);
       
   825 				}
       
   826 			}
       
   827 		}
       
   828 
       
   829 	if(iSeverity != EXMLFatal)
       
   830 		{
       
   831 	#ifdef _DEBUG
       
   832 		iIndentationLevel = 0;
       
   833 	#endif
       
   834 		
       
   835 		CMDXMLElement* parentElement = iXMLDoc->DocumentElement();
       
   836 
       
   837 		TInt error = KErrNone;
       
   838 
       
   839 		if(!parentElement->CheckChildren())
       
   840 			{
       
   841 			error = KErrNotSupported;
       
   842 			SetError(KErrXMLInvalidChild, EXMLWorkable);
       
   843 			}
       
   844 		
       
   845 		if(iOutputProlog)
       
   846 			{
       
   847 			// Output document level information if required.  MMS conformance requires no Version
       
   848 			// or DocType tag, so we may not want to output them.
       
   849 			if(iSeverity != EXMLFatal)
       
   850 				{
       
   851 				WriteFileL(iXMLDoc->VersionTag());
       
   852 				}
       
   853 			if(iSeverity != EXMLFatal)
       
   854 				{
       
   855 				WriteFileL(KNewLine);
       
   856 				}
       
   857 			if(iSeverity != EXMLFatal)
       
   858 				{
       
   859 				WriteFileL(iXMLDoc->DocTypeTag());
       
   860 				}
       
   861 			if(iSeverity != EXMLFatal)
       
   862 				{
       
   863 				WriteFileL(KNewLine);
       
   864 				}
       
   865 			}
       
   866 			
       
   867 		// Output the contents of the DOM tree
       
   868 		if(iSeverity != EXMLFatal)
       
   869 			{
       
   870 			error = ComposeL();
       
   871 			if(iSeverity != EXMLFatal)
       
   872 				{
       
   873 				if(error != KErrNone)
       
   874 					{
       
   875 					SetError(error, EXMLIndeterminate);
       
   876 					}
       
   877 
       
   878 				WriteFileL(KNewLine);
       
   879 				}
       
   880 			}
       
   881 
       
   882 		if(iSeverity != EXMLFatal)
       
   883 			{
       
   884 			error = FlushOutputBufferL();
       
   885 
       
   886 			if(error != KErrNone)
       
   887 				{
       
   888 				SetError(error, EXMLIndeterminate);
       
   889 				}
       
   890 			}
       
   891 		}
       
   892 
       
   893 	iXMLFile.Close();
       
   894 
       
   895 	if (iOnlyCalculatingSize)
       
   896 		{
       
   897 		*iSize = iSizeTally;
       
   898 		}
       
   899 
       
   900 	iComposerObserver->ComposeFileCompleteL();
       
   901 	}
       
   902 
       
   903 
       
   904 TInt CMDXMLComposer::ComposeL()
       
   905 //
       
   906 // Function to output the contents of the node as XML to some output stream.
       
   907 // @param aComposer The composer to use - provides access to output and entity conversion
       
   908 // @return Returns KerrNone if successful or a file write error
       
   909 // @leave Can Leave due to OOM.
       
   910 //
       
   911 	{
       
   912 	CMDXMLNode* nextPtr;
       
   913 	TInt error = KErrNone;
       
   914 	nextPtr = iXMLDoc->DocumentElement()->FirstChild();
       
   915 
       
   916 
       
   917 	while(error == KErrNone && nextPtr != NULL)
       
   918 		{
       
   919 		// compose the start tag of the current element
       
   920 		error = ComposeStartTagL(*nextPtr);
       
   921 
       
   922 		if(error == KErrNone)
       
   923 			{
       
   924 			// move to the first child is there is one
       
   925 			if(nextPtr->FirstChild() != NULL)
       
   926 				{
       
   927 				nextPtr = nextPtr->FirstChild();
       
   928 				}
       
   929 			else
       
   930 				{
       
   931 				// EndTag is only output if HasChildNodes() == TRUE
       
   932 				error = ComposeEndTagL(*nextPtr);
       
   933 
       
   934 				// move to the next sibling if exists
       
   935 				if(nextPtr->NextSibling() != NULL)
       
   936 					{
       
   937 					nextPtr = nextPtr->NextSibling();
       
   938 					}
       
   939 
       
   940 				// no siblings, move back to parent and close parent tag
       
   941 				else
       
   942 					{
       
   943 					// might need to go up several layers so WHILE rather than IF
       
   944 					while(nextPtr != NULL && nextPtr->NextSibling() == NULL && error == KErrNone)
       
   945 						{
       
   946 						nextPtr = nextPtr->ParentNode();
       
   947 						if(nextPtr != NULL)
       
   948 							{
       
   949 							error = ComposeEndTagL(*nextPtr);
       
   950 							}
       
   951 						}
       
   952 
       
   953 					// if we've stopped at an element with further siblings
       
   954 					if(nextPtr != NULL && nextPtr->NextSibling() != NULL)
       
   955 						{
       
   956 						nextPtr = nextPtr->NextSibling();
       
   957 						}
       
   958 					}
       
   959 				}
       
   960 			}
       
   961 		}
       
   962 
       
   963 	return error;
       
   964 	}
       
   965 
       
   966 
       
   967 EXPORT_C TInt CMDXMLComposer::ComposeStartTagL(CMDXMLNode& aNode)
       
   968  //
       
   969  // Outputs a start tag for the node which includes the
       
   970  // tag name and all attribute name value pairs currently
       
   971  // specified.  If the node is an empty node then it
       
   972  // makes the tag an empty node tag, otherwise it creates
       
   973  // a start tag.
       
   974  // @param aNode The Node for which the start tag is being written
       
   975  // @return Returns KerrNone if successful or a file write error
       
   976  // 
       
   977 	{
       
   978 	TInt error = KErrNone;
       
   979 
       
   980 	switch (aNode.NodeType())
       
   981 		{
       
   982 		case CMDXMLNode::ETextNode:
       
   983 			error = iEntityConverter->OutputComposedTextL(this, ((CMDXMLText&)aNode).Data());
       
   984 			break;
       
   985 		case CMDXMLNode::ECDATASectionNode:
       
   986 			error = OutputCDataSectionL(((CMDXMLCDATASection&)aNode).Data());
       
   987 			// does nothing
       
   988 			break;
       
   989 		case CMDXMLNode::EProcessingInstructionNode:
       
   990 			error = OutputProcessingInstructionL(((CMDXMLProcessingInstruction&)aNode).Data());
       
   991 			break;
       
   992 		case CMDXMLNode::ECommentNode:
       
   993 			error = OutputCommentL(((CMDXMLComment&)aNode).Data());
       
   994 			break;
       
   995 		case CMDXMLNode::EDocumentNode:
       
   996 			// does nothing
       
   997 			break;
       
   998 		case CMDXMLNode::EElementNode:
       
   999 			error = OutputStartOfElementTagL(aNode.NodeName());
       
  1000 			TInt attIndex;
       
  1001 			// Output all attributes in a loop
       
  1002 			for(attIndex = 0 ; (error == KErrNone && attIndex < ((CMDXMLElement&)aNode).NumAttributes()); attIndex ++ )
       
  1003 				{
       
  1004 				TPtrC attributeValue;	
       
  1005 				TPtrC attributeName;
       
  1006 				error = ((CMDXMLElement&)aNode).AttributeDetails(attIndex, attributeName, attributeValue);
       
  1007 				if(error == KErrNone)
       
  1008 					error = OutputAttributeL(attributeName, attributeValue);
       
  1009 				}
       
  1010 
       
  1011 
       
  1012 			if( error == KErrNone )
       
  1013 				{
       
  1014 				error = OutputEndOfElementTagL(aNode.HasChildNodes());
       
  1015 				}
       
  1016 			break;
       
  1017 		default:
       
  1018 			// does nothing
       
  1019 			break;
       
  1020 
       
  1021 
       
  1022 		}
       
  1023 
       
  1024 	return error;
       
  1025 	}
       
  1026 
       
  1027 EXPORT_C TInt CMDXMLComposer::ComposeEndTagL(CMDXMLNode& aNode)
       
  1028 //
       
  1029 // Outputs an end tag for the node.
       
  1030 // @param aNode the node for which the tag is being written.
       
  1031 // @return Returns KerrNone if successful or a file write error
       
  1032 //
       
  1033 	{
       
  1034 	TInt error = KErrNone;
       
  1035 
       
  1036 	if (aNode.NodeType() == CMDXMLNode::EElementNode && aNode.NodeName() != KXMLDocumentElementNodeName)
       
  1037 		{
       
  1038 		if(aNode.HasChildNodes())
       
  1039 			{
       
  1040 			error = OutputEndTagL(aNode.NodeName());
       
  1041 			}
       
  1042 		}
       
  1043 		
       
  1044 
       
  1045 	return error;
       
  1046 	}
       
  1047 
       
  1048 //==================================================================================
       
  1049 
       
  1050 TInt CMDXMLComposer::WriteFileL(const TDesC& aStringToWrite)
       
  1051 //
       
  1052 // Function to write string to required file format - handles format conversion
       
  1053 // @param aStringToWrite the string to output
       
  1054 // @return returns KERRNone if successful or a file write error.
       
  1055 //
       
  1056 	{
       
  1057 	TInt error = KErrNone;
       
  1058 	TInt outputBufferLength = iOutputBuffer.Length();
       
  1059 	TInt additionalLength = aStringToWrite.Length();
       
  1060 
       
  1061 	if(outputBufferLength + additionalLength <= KWriteBufferLen)
       
  1062 		{
       
  1063 		iOutputBuffer.Append(aStringToWrite);
       
  1064 		}
       
  1065 	else
       
  1066 		{
       
  1067 		iOutputBuffer.Append(aStringToWrite.Left(KWriteBufferLen - outputBufferLength));
       
  1068 		error = FlushOutputBufferL();
       
  1069 		iOutputBuffer.Zero();
       
  1070 		WriteFileL(aStringToWrite.Right(additionalLength - (KWriteBufferLen - outputBufferLength)));
       
  1071 		}		
       
  1072 
       
  1073 	return error;
       
  1074 	}
       
  1075 
       
  1076 //==================================================================================
       
  1077 #define DES_AS_8_BIT(str) (TPtrC8((TText8*)((str).Ptr()), (str).Size()))
       
  1078 
       
  1079 TInt CMDXMLComposer::FlushOutputBufferL()
       
  1080 //
       
  1081 // Function to write string to required file format - handles format conversion
       
  1082 // @param aStringToWrite the string to output
       
  1083 // @return returns KERRNone if successful or a file write or conversion error.
       
  1084 //
       
  1085 	{
       
  1086 	TInt error = KErrNone;
       
  1087 
       
  1088 	if (!iOnlyCalculatingSize)
       
  1089 		{
       
  1090 		if(iXMLFile.SubSessionHandle() == KNullHandle)
       
  1091 			{
       
  1092 			return KErrBadHandle;
       
  1093 			}
       
  1094 		}
       
  1095 
       
  1096 	// All text is processed internally as unicode.  If we've been asked to output
       
  1097 	// another format (Ascii or Utf-8) we need to translate it to that format using
       
  1098 	// charconv before writing the file.  
       
  1099 	switch(iFileType)
       
  1100 		{
       
  1101 		case EAscii:
       
  1102 		case EUtf8:
       
  1103 			{
       
  1104 			// We need to convert in a loop as charconv only allows 25 untranslatable
       
  1105 			// characters per block of text.  convResult tells us how many characters
       
  1106 			// were left untranslated at the end of iOutputBuffer so we only look at
       
  1107 			// that many characters on the right hand of iOutputBuffer.  Initially we
       
  1108 			// don't have any characters translated so convResult is the length of
       
  1109 			// iOutputBuffer.  Each time through the loop write out the chunk we've
       
  1110 			// converted.  If there's an error writing the file or doing the character
       
  1111 			// conversion we give up.
       
  1112 			TInt convResult = iOutputBuffer.Length();
       
  1113 			while((convResult > 0) && (error == KErrNone))
       
  1114 				{
       
  1115 				HBufC8* narrow = HBufC8::NewLC(convResult);
       
  1116 				TPtr8 narrowPtr = narrow->Des();
       
  1117 				if(iFileType == EAscii)
       
  1118 					{
       
  1119 					convResult = iCharconv->ConvertFromUnicode(narrowPtr, iOutputBuffer.Right(convResult));
       
  1120 					}
       
  1121 				else // iFileType == EUtf8
       
  1122 					{
       
  1123 					convResult = CnvUtfConverter::ConvertFromUnicodeToUtf8(narrowPtr, iOutputBuffer.Right(convResult));
       
  1124 					}
       
  1125 
       
  1126 				if(convResult >= 0)
       
  1127 					{
       
  1128 					iSizeTally += narrow->Size();
       
  1129 
       
  1130 					if (!iOnlyCalculatingSize)
       
  1131 						{
       
  1132 						error = iXMLFile.Write(narrow->Des());
       
  1133 						}
       
  1134 					}
       
  1135 				else
       
  1136 					{
       
  1137 					error = convResult;
       
  1138 					}
       
  1139 				CleanupStack::PopAndDestroy(narrow);
       
  1140 				} 
       
  1141 			break;
       
  1142 			}
       
  1143 
       
  1144 		case EUnicode:
       
  1145 			{
       
  1146 			TPtrC  output16 = iOutputBuffer;
       
  1147 			TPtrC8 output = DES_AS_8_BIT(output16);
       
  1148 			
       
  1149 			iSizeTally += output.Size();
       
  1150 
       
  1151 			if (!iOnlyCalculatingSize)
       
  1152 				{
       
  1153 				error = iXMLFile.Write(output);
       
  1154 				}
       
  1155 
       
  1156 			break;
       
  1157 			}
       
  1158 
       
  1159 		default:
       
  1160 			error = KErrNotSupported;
       
  1161 			break;
       
  1162 		}
       
  1163 
       
  1164 	if(error != KErrNone)
       
  1165 		{
       
  1166 		SetError(error, EXMLFatal);
       
  1167 		}
       
  1168 
       
  1169 	return error;	
       
  1170 	}
       
  1171 
       
  1172 //==================================================================================
       
  1173 
       
  1174 EXPORT_C void CMDXMLComposer::SetError(const TInt aErrorCode, const TXMLErrorCodeSeverity aSeverity)
       
  1175 //
       
  1176 // Sets iError to new errorcode if more serious than any error so far encountered
       
  1177 //
       
  1178 	{
       
  1179 	if(iSeverity > aSeverity)
       
  1180 		{
       
  1181 		iSeverity = aSeverity;
       
  1182 		iError = aErrorCode;
       
  1183 		}
       
  1184 	}
       
  1185 
       
  1186 EXPORT_C void CMDXMLComposer::PlaceholderForRemovedExport1(MMDXMLComposerObserver* /*aComposerObserver*/)
       
  1187 	{
       
  1188 	User::Panic(KLDRIMPORT, KLdrImportedOrdinalDoesNotExist);
       
  1189 	}
       
  1190 
       
  1191 EXPORT_C void CMDXMLComposer::PlaceholderForRemovedExport2()
       
  1192 	{
       
  1193 	User::Panic(KLDRIMPORT, KLdrImportedOrdinalDoesNotExist);
       
  1194 	}
       
  1195 
       
  1196 EXPORT_C void CMDXMLComposer::PlaceholderForRemovedExport3()
       
  1197 	{
       
  1198 	User::Panic(KLDRIMPORT, KLdrImportedOrdinalDoesNotExist);
       
  1199 	}
       
  1200 
       
  1201 // End of File