diff -r 417699dc19c9 -r c7e9f1c97567 xml/legacyminidomparser/xmlparser/src/gmxmlcomposer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xml/legacyminidomparser/xmlparser/src/gmxmlcomposer.cpp Mon Sep 13 13:16:40 2010 +0530 @@ -0,0 +1,1201 @@ +// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// GMXMLCOMPOSE.CPP +// @file +// This file contains the declaration of the generic CMDXMLComposer class +// which is responsible for creating an XML file +// from a given DOM structure. +// +// + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS +#include "gmxmldummydtd.h" +#endif + +_LIT(KXmlQuotation, """); + +// +// CMDXMLComposer // +// + +CMDXMLComposer::CMDXMLComposer(MMDXMLComposerObserver* aComposerObserver) : CActive(EPriorityNormal) +// +// Constructor +// + { + iComposerObserver = aComposerObserver; + iOutputProlog = ETrue; + CActiveScheduler::Add(this); + } + +CMDXMLComposer::CMDXMLComposer(MMDXMLComposerObserver* aComposerObserver, TBool aOutputProlog) : CActive(EPriorityNormal), + iOutputProlog(aOutputProlog) +// +// Constructor +// + { + iComposerObserver = aComposerObserver; + CActiveScheduler::Add(this); + } +//================================================================================== + +EXPORT_C CMDXMLComposer::~CMDXMLComposer() + { + Cancel(); + delete iEntityConverter; + delete iCharconv; + + iXMLFile.Close(); + } + +//================================================================================== + +void CMDXMLComposer::BaseConstructL() + { + iCharconv = CCnvCharacterSetConverter::NewL(); + iCharconv->SetDowngradeForExoticLineTerminatingCharacters( + CCnvCharacterSetConverter::EDowngradeExoticLineTerminatingCharactersToJustLineFeed); + } + +//================================================================================== + +EXPORT_C CMDXMLComposer* CMDXMLComposer::NewL(MMDXMLComposerObserver* aComposerObserver) +// +// Two phase static factory function constructor +// @param aEntityStrings the string table which lists the entity references and conversion +// @return Created CMDXMLComposer +// @leave can Leave due to OOM +// + { + CMDXMLComposer* self = NewLC(aComposerObserver); + CleanupStack::Pop(self); + return self; + } + +//================================================================================== + +EXPORT_C CMDXMLComposer* CMDXMLComposer::NewL(MMDXMLComposerObserver* aComposerObserver, TBool aOutputProlog) +// +// Two phase static factory function constructor +// @param aEntityStrings the string table which lists the entity references and conversion +// @param aOutputProlog Whether the Doctype and Version tags should be output. This is +// provided for MMS conformance. +// @return Created CMDXMLComposer +// @leave can Leave due to OOM +// + { + CMDXMLComposer* self = NewLC(aComposerObserver, aOutputProlog); + CleanupStack::Pop(self); + return self; + } + +//================================================================================== + +EXPORT_C CMDXMLComposer* CMDXMLComposer::NewLC(MMDXMLComposerObserver* aComposerObserver) +// +// Two phase static factory function constructor +// @param aEntityStrings the string table which lists the entity references and conversion +// @return Created CMDXMLComposer +// @leave can Leave due to OOM +// + { + CMDXMLComposer* self = new (ELeave) CMDXMLComposer(aComposerObserver); + CleanupStack::PushL(self); + self->ConstructL(); + return self; + } + +//================================================================================== + +EXPORT_C CMDXMLComposer* CMDXMLComposer::NewLC(MMDXMLComposerObserver* aComposerObserver, TBool aOutputProlog) +// +// Two phase static factory function constructor +// @param aEntityStrings the string table which lists the entity references and conversion +// @param aOutputProlog Whether the Doctype and Version tags should be output. This is +// provided for MMS conformance. +// @return Created CMDXMLComposer +// @leave can Leave due to OOM +// + { + CMDXMLComposer* self = new (ELeave) CMDXMLComposer(aComposerObserver, aOutputProlog); + CleanupStack::PushL(self); + self->ConstructL(); + return self; + } + +//================================================================================== + +void CMDXMLComposer::ConstructL() +// +// Second stage constructor +// @param aEntityStrings the string table which lists the entity references and conversion +// + { + BaseConstructL(); + CMDXMLEntityConverter* entityConverter = new(ELeave) CMDXMLEntityConverter(); + SetEntityConverter(entityConverter); + } + + +//================================================================================== + +void CMDXMLComposer::InitialiseCompose(CMDXMLDocument* aDocument, TXMLFileType aFileType) + { + Cancel(); + + iError = KErrNone; + iSeverity = EXMLNone; + iOutputBuffer.Zero(); + + iXMLDoc = aDocument; + iFileType = aFileType; + + iOnlyCalculatingSize = EFalse; + iSizeTally = 0; + } + +EXPORT_C TInt CMDXMLComposer::ComposeFile(RFs aRFs, const TDesC& aFileToCompose, CMDXMLDocument* aDocument, TXMLFileType aFileType) +/** Starts file composition. + +This function can not be called if there is an outstanding size calculation or compose +operation in progress. If it is necessary to run two asynchronous operations in parallel +then two instances of the CMDXMLComposer are needed. + +@param aRFS File system to use +@param aFileToCompose Name of file to create +@param aDocument The document object to compose to the file +@return KERRNone if successful +**/ + { + InitialiseCompose(aDocument, aFileType); + iRFs = aRFs; + TInt error = KErrNone; + + if(iXMLDoc == NULL) + { + error = KErrNotSupported; + } + else + { + switch(iFileType) + { + case EAscii: + { + error = iXMLFile.Replace(aRFs, aFileToCompose, EFileWrite | EFileStream); + break; + } + case EUnicode: + error = iXMLFile.Replace(aRFs, aFileToCompose, EFileWrite | EFileStream); + if(error == KErrNone) + { + // append Unicode File identifier to start of output text + iOutputBuffer.Append(CEditableText::EByteOrderMark); + } + break; + case EUtf8: + { + error = iXMLFile.Replace(aRFs, aFileToCompose, EFileWrite | EFileStream); + break; + } + default: + error = KErrNotSupported; + break; + } + } + + if(error == KErrNone) + { + SetActive(); + TRequestStatus* s=&iStatus; + User::RequestComplete(s, KErrNone); + } + else + { + SetError(error, EXMLFatal); + } + + return error; + } + +/** Starts file composition to an open file handle. + +This function must not be called when file sizing is in progress. If it is necessary to calulate +the size and generate the XML simultaneously then two instances of the composer should be used, +one for sizing and one for composition. + +@param aFileHandleToCompose An open file handle to write to. Ownership of the file handle is passed even if an error occurs. +@param aDocument The document object to compose to the file. +@param aFileType Type of the output file. +@return KErrNone if successful. +*/ +EXPORT_C TInt CMDXMLComposer::ComposeFile(RFile& aFileHandleToCompose, CMDXMLDocument* aDocument, TXMLFileType aFileType) + { + InitialiseCompose(aDocument, aFileType); + iXMLFile = aFileHandleToCompose; + TInt error = KErrNone; + + if(iXMLDoc == NULL) + { + error = KErrNotSupported; + } + else + { + switch(iFileType) + { + case EUnicode: + { + // append Unicode File identifier to start of output text + iOutputBuffer.Append(CEditableText::EByteOrderMark); + } + case EAscii: + case EUtf8: + break; + + default: + error = KErrNotSupported; + break; + } + } + + if(error == KErrNone) + { + iStatus = KRequestPending; + SetActive(); + TRequestStatus* s=&iStatus; + User::RequestComplete(s, KErrNone); + } + else + { + iXMLFile.Close(); + SetError(error, EXMLFatal); + } + + return error; + } + +//================================================================================== + +/** Starts calculating the size of the XML output without actually writing it to the file. + +This process is asyncronous, the size value is only updated when ComposeFileComplete +is called on the MMDXMLComposerObserver passed in in the NewL. + +This function can not be called if there is an outstanding size calculation or compose +operation in progress. If it is necessary to run two asynchronous operations in parallel +then two instances of CMDXMLComposer are needed. + +@param aSize Will be set to the size of the XML document when composition has completed. +@param aDocument The document object to size +@param aFileType Type of the output file, required because it will affect the size of the XML +@return KErrNone if successful */ + +EXPORT_C TInt CMDXMLComposer::CalculateFileSize(TInt& aSize, CMDXMLDocument* aDocument, TXMLFileType aFileType) + { + Cancel(); + + iError = KErrNone; + iSeverity = EXMLNone; + iOutputBuffer.Zero(); + + iXMLDoc = aDocument; + iFileType = aFileType; + TInt error = KErrNone; + + if (iFileType == EUnicode) + { + // The size tally must be incremented by two characters because the unicode byte marker + // gets added in the ComposeFile function that does not get called when we are calculating + // the size. + iSizeTally = 2; + } + else + { + iSizeTally = 0; + } + + iSize = &aSize; + iOnlyCalculatingSize = ETrue; + + if(iXMLDoc == NULL) + { + error = KErrNotSupported; + } + + if(error == KErrNone) + { + SetActive(); + TRequestStatus* s=&iStatus; + User::RequestComplete(s, KErrNone); + } + else + { + SetError(error, EXMLFatal); + } + + return error; + } + +//================================================================================== + +EXPORT_C TInt CMDXMLComposer::Error() const + { + return iError; + } + +//================================================================================== + +EXPORT_C TXMLErrorCodeSeverity CMDXMLComposer::ErrorSeverity() const + { + return iSeverity; + } + +//================================================================================== + +EXPORT_C CMDXMLEntityConverter* CMDXMLComposer::EntityConverter() const + { + return iEntityConverter; + } + +//================================================================================== + +TInt CMDXMLComposer::OutputCommentL(const TDesC& aComment) +// +// Output a comment +// @param aComment the comment text to output +// @return KERRNone if successful, otherwise a file writing error. +// + { + TInt error = KErrNone; + + if(iSeverity != EXMLFatal) + { + error = WriteFileL(KNewLine); + } + +#ifdef _DEBUG + for(TInt loopIndex = 0; loopIndex < iIndentationLevel; loopIndex++) + { + if(iSeverity != EXMLFatal) + { + error = WriteFileL(KTab); + } + } +#endif + + if(iSeverity != EXMLFatal) + { + error = WriteFileL(KXMLStartComment); + } + + if(iSeverity != EXMLFatal) + { + error = WriteFileL(aComment); + } + + if(iSeverity != EXMLFatal) + { + error = WriteFileL(KXMLEndComment); + } + + return error; + } + +//================================================================================== + +TInt CMDXMLComposer::OutputProcessingInstructionL(const TDesC& aInstruction) +// +// Output a Processing Instruction +// @param aInstruction the Processing Instruction text to output +// @return KERRNone if successful, otherwise a file writing error. +// + { + TInt error = KErrNone; + + if(iSeverity != EXMLFatal) + { + error = WriteFileL(KNewLine); + } + +#ifdef _DEBUG + for(TInt loopIndex = 0; loopIndex < iIndentationLevel; loopIndex++) + { + if(iSeverity != EXMLFatal) + { + error = WriteFileL(KTab); + } + } +#endif + + if(iSeverity != EXMLFatal) + { + error = WriteFileL(KXMLStartProcessingInstruction); + } + + if(iSeverity != EXMLFatal) + { + error = WriteFileL(aInstruction); + } + + if(iSeverity != EXMLFatal) + { + error = WriteFileL(KXMLEndProcessingInstruction); + } + + return error; + } + + +//================================================================================== + +TInt CMDXMLComposer::OutputCDataSectionL(const TDesC& aCDataSection) +// +// Output a CDataSection +// @param aCDataSection the data section text to output +// @return KERRNone if successful, otherwise a file writing error. +// + { + TInt error = KErrNone; + +#ifdef _DEBUG + for(TInt loopIndex = 0; loopIndex < iIndentationLevel; loopIndex++) + { + if(iSeverity != EXMLFatal) + { + error = WriteFileL(KTab); + } + } +#endif + + if(iSeverity != EXMLFatal) + { + error = WriteFileL(KXMLStartCDataSection); + } + + if(iSeverity != EXMLFatal) + { + error = WriteFileL(aCDataSection); + } + + if(iSeverity != EXMLFatal) + { + error = WriteFileL(KXMLEndCDataSection); + } + + return error; + } + +//================================================================================== +//Defect fix for INC036136- Enable the use of custom entity converters in GMXML + +EXPORT_C TInt CMDXMLComposer::OutputDataL(const TDesC& aData) +// +// Output raw data +// it's only intended to be used from within a custom entity converter as +// it relies on a Composer sesssion already being in progress +// @param the data to be output +// @return KERRNone if successful, otherwise a file writing error. +// + { + TInt error = KErrNone; + + if(iSeverity != EXMLFatal) + { + if(aData.Find(KQuotation) != KErrNotFound) + { + error = ReplaceXmlCharactersL(aData, KQuotation); + } + else + { + error = WriteFileL(aData); + } + } + + return error; + } + +//================================================================================== +/* Before writing to xml file, search for special character like quotation ("). + if it exist then replace it with " and then write it to xml file. + Refer section 5 of below URL for more information. + http://www.xmlnews.org/docs/xml-basics.html + @param aXmlData the data to be output + @param aString the special character to search in aXmlData + @return KERRNone if successful, otherwise a file writing error. */ + +TInt CMDXMLComposer::ReplaceXmlCharactersL(const TDesC16& aXmlData, const TDesC& aString) + { + TInt xmlDataIndex; + const TDesC& quot = KXmlQuotation; + HBufC16* xmlData = aXmlData.AllocL(); + + while((xmlDataIndex = (xmlData->Des()).Find(aString)) != KErrNotFound) + { + HBufC16* temp = HBufC::NewLC(((xmlData->Des()).Length() - 1) + quot.Length()); + TPtr16 tempPtr = temp->Des(); + tempPtr.Append((xmlData->Des()).Left(xmlDataIndex)); + tempPtr.Append(quot); + tempPtr.Append((xmlData->Des()).Right((xmlData->Des()).Length() - (xmlDataIndex + 1))); + delete xmlData; + xmlData = NULL; + xmlData = tempPtr.AllocL(); + CleanupStack::PopAndDestroy(); // temp + } + TInt error = WriteFileL((xmlData->Des())); + delete xmlData; + xmlData = NULL; + return error; + } + +//================================================================================== + +EXPORT_C void CMDXMLComposer::SetEntityConverter(CMDXMLEntityConverter* aEntityConverter) +/* + * Sets the entity converter to be used + * and take ownership of the passed entity converter + * @param aEntityConverter The entity converter to be used + */ + { + delete iEntityConverter; + iEntityConverter = aEntityConverter; + } + +//End Defect fix for INC036136 +//================================================================================== + +EXPORT_C TInt CMDXMLComposer::OutputStartOfElementTagL(const TDesC& aElementName) +// +// Output a start of element tag +// @param aElementName the name of the tag to output +// @return KERRNone if successful, otherwise a file writing error. +// + { + TInt error = KErrNone; + +#ifdef _DEBUG + for(TInt loopIndex = 0; loopIndex < iIndentationLevel; loopIndex++) + { + if(iSeverity != EXMLFatal) + { + error = WriteFileL(KTab); + } + } + iIndentationLevel++; +#endif + + if(iSeverity != EXMLFatal) + { + error = WriteFileL(KXMLStartTag); + } + + if(iSeverity != EXMLFatal) + { + error = WriteFileL(aElementName); + } + + return error; + } + +//================================================================================== + +EXPORT_C TInt CMDXMLComposer::OutputEndOfElementTagL(const TBool aHasChildren) +// +// Output an end of element start tag +// @param aHasChildren true if the element has children +// @return KERRNone if successful, otherwise a file writing error. +// + { + TInt error = KErrNone; + + if(iSeverity != EXMLFatal) + { + if(aHasChildren) + { + error = WriteFileL(KXMLEndTag); + } + else + { + error = WriteFileL(KXMLEndStartTag); + + #ifdef _DEBUG + iIndentationLevel--; + #endif + } + } + + return error; + } + +//================================================================================== + +TInt CMDXMLComposer::OutputEndTagL(const TDesC& aElementName) +// +// Output an end of element tag +// @param aElementName the name of the tag to output +// @return KERRNone if successful, otherwise a file writing error. +// + { + TInt error = KErrNone; + +#ifdef _DEBUG + iIndentationLevel--; + for(TInt loopIndex = 0; loopIndex < iIndentationLevel; loopIndex++) + { + if(iSeverity != EXMLFatal) + { + error = WriteFileL(KTab); + } + } +#endif + + if(iSeverity != EXMLFatal) + { + error = WriteFileL(KXMLStartEndTag); + } + + if(iSeverity != EXMLFatal) + { + error = WriteFileL(aElementName); + } + + if(iSeverity != EXMLFatal) + { + error = WriteFileL(KXMLEndTag); + } + + return error; + } + + + + + +//================================================================================== + +EXPORT_C TInt CMDXMLComposer::OutputAttributeL(const TDesC& aAttributeName, const TDesC& aAttributeValue) +// +// Output an attribute - name and value. +// @param aAttributeName the name of the attribute to output +// @param aAttributeValue the text of the attribute value to output +// @return KERRNone if successful, otherwise a file writing error. +// + { + TInt error = KErrNone; + + if(iSeverity != EXMLFatal) + { + error = WriteFileL(KSingleSpace); + } + + if(iSeverity != EXMLFatal) + { + error = WriteFileL(aAttributeName); + } + + if(iSeverity != EXMLFatal) + { + error = WriteFileL(KEqualSign); + } + + if(iSeverity != EXMLFatal) + { + error = WriteFileL(KQuotation); + } + + if(iSeverity != EXMLFatal) + { + // Work along the attribute value in sections. We have two markers in the attribute, + // one at the beginning of the section we're working on and one at the end. Initially + // beginSection is the start of the string, 0, the end of the section is the first + // CDataSection we find. + // beginSection is an offset within the string, endSection is an offset from that + TInt beginSection = 0; + TInt endSection = aAttributeValue.Find(KXMLStartCDataSection); + + // We've found at least one CDataSection + while(endSection != KErrNotFound) + { + // Entity convert this plain text section + TPtrC plainText = aAttributeValue.Mid(beginSection, endSection); + error = iEntityConverter->OutputComposedTextL(this, plainText); + + // Move on our markers. We start the new section at the end of the old one. + beginSection += endSection; + // The end of this section is the end of the CDataSection + endSection = TPtrC(aAttributeValue.Mid(beginSection)).Find(KXMLEndCDataSection); + if(endSection != KErrNotFound) + { + // The CDataSection ends at the beginning of the end tag, so we need to add + // on the length of the end tag before outputting it without conversion + endSection += TPtrC(KXMLEndCDataSection).Length(); + OutputDataL(aAttributeValue.Mid(beginSection, endSection)); + + // Now move on our markers again. Start at the end of the CDataSection, and + // continue to the beginning of the next one. + beginSection += endSection; + endSection = TPtrC(aAttributeValue.Mid(beginSection)).Find(KXMLStartCDataSection); + } + else + { + // There's an unterminated CDataSection in our attribute + error = KErrXMLBadAttributeValue; + } + } + + // There are no more CDataSections, entity convert the rest of the string + if(!error) + { + error = iEntityConverter->OutputComposedTextL(this, aAttributeValue.Mid(beginSection)); + } + } + + if(iSeverity != EXMLFatal) + { + error = WriteFileL(KQuotation); + } + + return error; + } + +//================================================================================== + +EXPORT_C TInt CMDXMLComposer::RunError(TInt aError) +// +// RunError function inherited from CActive base class - intercepts any Leave from +// the RunL() function, sets an appropriate errorcode and calls ComposeFileCompleteL +// + { + iSeverity = EXMLFatal; + iError = aError; + iXMLFile.Close(); + TRAPD(err, iComposerObserver->ComposeFileCompleteL()); + return err; + } + +//================================================================================== + +EXPORT_C void CMDXMLComposer::DoCancel() +// +// DoCancel function inherited from CActive base class +// + { + iXMLFile.Close(); + } + +//================================================================================== + +void CMDXMLComposer::RunL() +// +// RunL function inherited from CActive base class - does the actual composition +// @leave can Leave due to OOM +// + { + // If this is an ASCII file then check that we can load the character set converter + if(iSeverity != EXMLFatal) + { + if(iFileType == EAscii) + { + if (iCharconv->PrepareToConvertToOrFromL(KCharacterSetIdentifierAscii, iRFs)!= + CCnvCharacterSetConverter::EAvailable) + { + SetError( KErrNotSupported, EXMLFatal); + } + } + } + + if(iSeverity != EXMLFatal) + { + #ifdef _DEBUG + iIndentationLevel = 0; + #endif + + CMDXMLElement* parentElement = iXMLDoc->DocumentElement(); + + TInt error = KErrNone; + + if(!parentElement->CheckChildren()) + { + error = KErrNotSupported; + SetError(KErrXMLInvalidChild, EXMLWorkable); + } + + if(iOutputProlog) + { + // Output document level information if required. MMS conformance requires no Version + // or DocType tag, so we may not want to output them. + if(iSeverity != EXMLFatal) + { + WriteFileL(iXMLDoc->VersionTag()); + } + if(iSeverity != EXMLFatal) + { + WriteFileL(KNewLine); + } + if(iSeverity != EXMLFatal) + { + WriteFileL(iXMLDoc->DocTypeTag()); + } + if(iSeverity != EXMLFatal) + { + WriteFileL(KNewLine); + } + } + + // Output the contents of the DOM tree + if(iSeverity != EXMLFatal) + { + error = ComposeL(); + if(iSeverity != EXMLFatal) + { + if(error != KErrNone) + { + SetError(error, EXMLIndeterminate); + } + + WriteFileL(KNewLine); + } + } + + if(iSeverity != EXMLFatal) + { + error = FlushOutputBufferL(); + + if(error != KErrNone) + { + SetError(error, EXMLIndeterminate); + } + } + } + + iXMLFile.Close(); + + if (iOnlyCalculatingSize) + { + *iSize = iSizeTally; + } + + iComposerObserver->ComposeFileCompleteL(); + } + + +TInt CMDXMLComposer::ComposeL() +// +// Function to output the contents of the node as XML to some output stream. +// @param aComposer The composer to use - provides access to output and entity conversion +// @return Returns KerrNone if successful or a file write error +// @leave Can Leave due to OOM. +// + { + CMDXMLNode* nextPtr; + TInt error = KErrNone; + nextPtr = iXMLDoc->DocumentElement()->FirstChild(); + + + while(error == KErrNone && nextPtr != NULL) + { + // compose the start tag of the current element + error = ComposeStartTagL(*nextPtr); + + if(error == KErrNone) + { + // move to the first child is there is one + if(nextPtr->FirstChild() != NULL) + { + nextPtr = nextPtr->FirstChild(); + } + else + { + // EndTag is only output if HasChildNodes() == TRUE + error = ComposeEndTagL(*nextPtr); + + // move to the next sibling if exists + if(nextPtr->NextSibling() != NULL) + { + nextPtr = nextPtr->NextSibling(); + } + + // no siblings, move back to parent and close parent tag + else + { + // might need to go up several layers so WHILE rather than IF + while(nextPtr != NULL && nextPtr->NextSibling() == NULL && error == KErrNone) + { + nextPtr = nextPtr->ParentNode(); + if(nextPtr != NULL) + { + error = ComposeEndTagL(*nextPtr); + } + } + + // if we've stopped at an element with further siblings + if(nextPtr != NULL && nextPtr->NextSibling() != NULL) + { + nextPtr = nextPtr->NextSibling(); + } + } + } + } + } + + return error; + } + + +EXPORT_C TInt CMDXMLComposer::ComposeStartTagL(CMDXMLNode& aNode) + // + // Outputs a start tag for the node which includes the + // tag name and all attribute name value pairs currently + // specified. If the node is an empty node then it + // makes the tag an empty node tag, otherwise it creates + // a start tag. + // @param aNode The Node for which the start tag is being written + // @return Returns KerrNone if successful or a file write error + // + { + TInt error = KErrNone; + + switch (aNode.NodeType()) + { + case CMDXMLNode::ETextNode: + error = iEntityConverter->OutputComposedTextL(this, ((CMDXMLText&)aNode).Data()); + break; + case CMDXMLNode::ECDATASectionNode: + error = OutputCDataSectionL(((CMDXMLCDATASection&)aNode).Data()); + // does nothing + break; + case CMDXMLNode::EProcessingInstructionNode: + error = OutputProcessingInstructionL(((CMDXMLProcessingInstruction&)aNode).Data()); + break; + case CMDXMLNode::ECommentNode: + error = OutputCommentL(((CMDXMLComment&)aNode).Data()); + break; + case CMDXMLNode::EDocumentNode: + // does nothing + break; + case CMDXMLNode::EElementNode: + error = OutputStartOfElementTagL(aNode.NodeName()); + TInt attIndex; + // Output all attributes in a loop + for(attIndex = 0 ; (error == KErrNone && attIndex < ((CMDXMLElement&)aNode).NumAttributes()); attIndex ++ ) + { + TPtrC attributeValue; + TPtrC attributeName; + error = ((CMDXMLElement&)aNode).AttributeDetails(attIndex, attributeName, attributeValue); + if(error == KErrNone) + error = OutputAttributeL(attributeName, attributeValue); + } + + + if( error == KErrNone ) + { + error = OutputEndOfElementTagL(aNode.HasChildNodes()); + } + break; + default: + // does nothing + break; + + + } + + return error; + } + +EXPORT_C TInt CMDXMLComposer::ComposeEndTagL(CMDXMLNode& aNode) +// +// Outputs an end tag for the node. +// @param aNode the node for which the tag is being written. +// @return Returns KerrNone if successful or a file write error +// + { + TInt error = KErrNone; + + if (aNode.NodeType() == CMDXMLNode::EElementNode && aNode.NodeName() != KXMLDocumentElementNodeName) + { + if(aNode.HasChildNodes()) + { + error = OutputEndTagL(aNode.NodeName()); + } + } + + + return error; + } + +//================================================================================== + +TInt CMDXMLComposer::WriteFileL(const TDesC& aStringToWrite) +// +// Function to write string to required file format - handles format conversion +// @param aStringToWrite the string to output +// @return returns KERRNone if successful or a file write error. +// + { + TInt error = KErrNone; + TInt outputBufferLength = iOutputBuffer.Length(); + TInt additionalLength = aStringToWrite.Length(); + + if(outputBufferLength + additionalLength <= KWriteBufferLen) + { + iOutputBuffer.Append(aStringToWrite); + } + else + { + iOutputBuffer.Append(aStringToWrite.Left(KWriteBufferLen - outputBufferLength)); + error = FlushOutputBufferL(); + iOutputBuffer.Zero(); + WriteFileL(aStringToWrite.Right(additionalLength - (KWriteBufferLen - outputBufferLength))); + } + + return error; + } + +//================================================================================== +#define DES_AS_8_BIT(str) (TPtrC8((TText8*)((str).Ptr()), (str).Size())) + +TInt CMDXMLComposer::FlushOutputBufferL() +// +// Function to write string to required file format - handles format conversion +// @param aStringToWrite the string to output +// @return returns KERRNone if successful or a file write or conversion error. +// + { + TInt error = KErrNone; + + if (!iOnlyCalculatingSize) + { + if(iXMLFile.SubSessionHandle() == KNullHandle) + { + return KErrBadHandle; + } + } + + // All text is processed internally as unicode. If we've been asked to output + // another format (Ascii or Utf-8) we need to translate it to that format using + // charconv before writing the file. + switch(iFileType) + { + case EAscii: + case EUtf8: + { + // We need to convert in a loop as charconv only allows 25 untranslatable + // characters per block of text. convResult tells us how many characters + // were left untranslated at the end of iOutputBuffer so we only look at + // that many characters on the right hand of iOutputBuffer. Initially we + // don't have any characters translated so convResult is the length of + // iOutputBuffer. Each time through the loop write out the chunk we've + // converted. If there's an error writing the file or doing the character + // conversion we give up. + TInt convResult = iOutputBuffer.Length(); + while((convResult > 0) && (error == KErrNone)) + { + HBufC8* narrow = HBufC8::NewLC(convResult); + TPtr8 narrowPtr = narrow->Des(); + if(iFileType == EAscii) + { + convResult = iCharconv->ConvertFromUnicode(narrowPtr, iOutputBuffer.Right(convResult)); + } + else // iFileType == EUtf8 + { + convResult = CnvUtfConverter::ConvertFromUnicodeToUtf8(narrowPtr, iOutputBuffer.Right(convResult)); + } + + if(convResult >= 0) + { + iSizeTally += narrow->Size(); + + if (!iOnlyCalculatingSize) + { + error = iXMLFile.Write(narrow->Des()); + } + } + else + { + error = convResult; + } + CleanupStack::PopAndDestroy(narrow); + } + break; + } + + case EUnicode: + { + TPtrC output16 = iOutputBuffer; + TPtrC8 output = DES_AS_8_BIT(output16); + + iSizeTally += output.Size(); + + if (!iOnlyCalculatingSize) + { + error = iXMLFile.Write(output); + } + + break; + } + + default: + error = KErrNotSupported; + break; + } + + if(error != KErrNone) + { + SetError(error, EXMLFatal); + } + + return error; + } + +//================================================================================== + +EXPORT_C void CMDXMLComposer::SetError(const TInt aErrorCode, const TXMLErrorCodeSeverity aSeverity) +// +// Sets iError to new errorcode if more serious than any error so far encountered +// + { + if(iSeverity > aSeverity) + { + iSeverity = aSeverity; + iError = aErrorCode; + } + } + +EXPORT_C void CMDXMLComposer::PlaceholderForRemovedExport1(MMDXMLComposerObserver* /*aComposerObserver*/) + { + User::Panic(KLDRIMPORT, KLdrImportedOrdinalDoesNotExist); + } + +EXPORT_C void CMDXMLComposer::PlaceholderForRemovedExport2() + { + User::Panic(KLDRIMPORT, KLdrImportedOrdinalDoesNotExist); + } + +EXPORT_C void CMDXMLComposer::PlaceholderForRemovedExport3() + { + User::Panic(KLDRIMPORT, KLdrImportedOrdinalDoesNotExist); + } + +// End of File