--- /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 <f32file.h>
+#include <utf.h>
+
+#include <gmxmlconstants.h>
+#include <gmxmlnode.h>
+#include <gmxmldocument.h>
+#include <gmxmlelement.h>
+#include <gmxmlcomposer.h>
+#include <gmxmlentityconverter.h>
+#include <gmxmltext.h>
+#include <gmxmlprocessinginstruction.h>
+#include <gmxmlcomment.h>
+#include <gmxmlcdatasection.h>
+#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