xml/xmldomandxpath/src/xmlengineserializer/xmlengcontenthandler.cpp
changeset 0 e35f40988205
child 22 58e164f13314
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xml/xmldomandxpath/src/xmlengineserializer/xmlengcontenthandler.cpp	Thu Dec 17 09:29:21 2009 +0200
@@ -0,0 +1,419 @@
+// Copyright (c) 2006-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:
+// Content handler implementation
+//
+
+#include "xmlengcontenthandler.h"
+#include <xml/dom/xmlengerrors.h>
+#include <xml/dom/xmlengdeserializer.h>
+#include "xmlengdeserializerxop.h"
+#include <xml/dom/xmlengextendedcontenthandler.h>
+#include <xml/parserfeature.h>
+
+#include <xml/dom/xmlengserializeerrors.h>
+#include <bsul/clientmessage.h>
+
+CXmlEngContentHandler* CXmlEngContentHandler::NewL( CXmlEngDeserializer* aDeserializer,
+											   		MContentHandler* aContentHandler )
+	{
+	CXmlEngContentHandler* self = new (ELeave) CXmlEngContentHandler(aDeserializer, aContentHandler);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self); //self
+	return self;
+	}
+
+CXmlEngContentHandler::~CXmlEngContentHandler()
+	{
+	iCachedPrefixes.ResetAndDestroy();
+	iCachedUris.ResetAndDestroy();
+	iCachedErrors.Reset();
+	iStrPool.Close();
+	}
+
+CXmlEngContentHandler::CXmlEngContentHandler(CXmlEngDeserializer* aDeserializer, 
+									   		 MContentHandler* aContentHandler)
+: iDeserializer(aDeserializer),
+  iContentHandler(aContentHandler)
+	{
+	iSkipIncludeElement = 0;
+  	iSkipPrefixMapping = 0;
+	}
+
+void CXmlEngContentHandler::ConstructL()
+	{
+	iStrPool.OpenL();
+	}
+
+/**
+This method is a callback to indicate the start of the document.
+@param				aDocParam Specifies the various parameters of the document.
+@param				aDocParam.iCharacterSetName The character encoding of the document.
+@param				aErrorCode is the error code. 
+					If this is not KErrNone then special action may be required.
+*/
+void CXmlEngContentHandler::OnStartDocumentL(const RDocumentParameters& aDocParam, TInt aErrorCode)
+{
+	iContentHandler->OnStartDocumentL(aDocParam, aErrorCode);
+}
+
+
+/**
+This method is a callback to indicate the end of the document.
+@param				aErrorCode is the error code. 
+					If this is not KErrNone then special action may be required.
+*/
+void CXmlEngContentHandler::OnEndDocumentL(TInt aErrorCode)
+{
+	iContentHandler->OnEndDocumentL(aErrorCode);
+}
+
+
+/**
+This method is a callback to indicate an element has been parsed.
+@param				aElement is a handle to the element's details.
+@param				aAttributes contains the attributes for the element.
+@param				aErrorCode is the error code.
+					If this is not KErrNone then special action may be required.
+*/
+void CXmlEngContentHandler::OnStartElementL(const RTagInfo& aElement,
+								 const RAttributeArray& aAttributes, 
+								 TInt aErrorCode)
+{
+	_LIT8(KInclude, "Include");
+	_LIT8(KXopIncludeUri, "http://www.w3.org/2004/08/xop/include");
+	_LIT8(KHref, "href");
+	_LIT8(KHrefUriEmpty, ""); 
+	
+	TBool xopInclude = EFalse;
+	
+	if(iSkipIncludeElement)
+		{
+		if( aElement.LocalName().DesC() == KInclude
+	    	&& aElement.Uri().DesC() == KXopIncludeUri)
+			{
+			xopInclude = ETrue;
+			++iSkipIncludeElement;				
+			}		
+		return;
+		}
+
+	MXmlEngExtendedHandler* ext = (MXmlEngExtendedHandler*)iContentHandler->GetExtendedInterface(MXmlEngExtendedHandler::EExtInterfaceUid);
+
+	// determine if this element is xop:Include
+	if( xopInclude ||
+		(aElement.LocalName().DesC() == KInclude &&
+	    aElement.Uri().DesC() == KXopIncludeUri))
+		{
+		for ( TInt i = 0; i < aAttributes.Count(); i++)
+			{
+			if( aAttributes[i].Attribute().LocalName().DesC() == KHref
+				&& aAttributes[i].Attribute().Uri().DesC() == KHrefUriEmpty)
+				{
+				TPtrC8 cidValue;
+				TPtrC8 data;
+				cidValue.Set(CidValue(aAttributes[i].Value().DesC()));
+				if( (CXmlEngDeserializer*)iDeserializer->ExternalData() 
+					 && iDeserializer->GetDataContainer(cidValue) )
+					{
+					++iSkipIncludeElement;
+					iSkipPrefixMapping = ETrue;
+					if(ext)
+						ext->OnDataContainerL(*iDeserializer->GetDataContainer(cidValue), KErrNone);	
+					}
+				else if(((CXmlEngDeserializerXOP*)iDeserializer)->GetData(cidValue, data) == KErrNone)					
+					{
+					++iSkipIncludeElement;
+					iSkipPrefixMapping = ETrue;
+					if(ext)
+						{
+						if(iDeserializer->ParsingOptions().iOptions & TXmlEngParsingOptions::KOptionEncodeToBase64)
+							{
+							//TImCodecB64 base64Codec; 
+							// The encoded length of base64 is about twice (use 3x) decoded length
+							HBufC8* data64 = HBufC8::NewLC(3*data.Size());  
+							TPtr8 data64Ptr = data64->Des();
+							// Encode to the base64 Content-Transfer-Encoding
+							//base64Codec.Encode(data, data64Ptr);
+							using namespace BSUL;
+							Base64Codec::Encode(data, data64Ptr);
+							if(data64Ptr.Length() == 0)
+								{
+								User::Leave(KErrGeneral);
+								}
+							ext->OnBinaryContentL(data64Ptr,cidValue,aErrorCode);
+							CleanupStack::PopAndDestroy(); //data64							
+							}
+						else
+							{
+							ext->OnBinaryContentL(data,cidValue,aErrorCode);			
+							}
+						}
+						
+					}
+				else
+					{
+					User::Leave(KXmlEngErrBinDataNotFound);
+					//iContentHandler->OnStartElementL(aElement, aAttributes, aErrorCode);
+					}						
+				}
+			} //for
+		}
+
+	if(!iSkipIncludeElement)
+		{
+		if(iCachedUris.Count())
+			{
+			RString prefix;
+			RString uri;
+			for(TInt i = 0; i < iCachedPrefixes.Count(); i++)
+				{
+				prefix = iStrPool.OpenStringL(iCachedPrefixes[i]->Des());
+				CleanupClosePushL(prefix);
+				uri = iStrPool.OpenStringL(iCachedUris[i]->Des());
+				CleanupClosePushL(uri);
+				iContentHandler->OnStartPrefixMappingL(prefix, uri, iCachedErrors[i]);
+				CleanupStack::PopAndDestroy(&uri);
+				CleanupStack::PopAndDestroy(&prefix);
+				}						
+			}
+		if(iDeserializer->IsFeatureEnabled(EConvertTagsToLowerCase))
+			{
+			RTagInfo elementTag = ConvertNameToLowerCaseL(aElement);
+			CleanupClosePushL(elementTag);
+			iContentHandler->OnStartElementL(elementTag, aAttributes, aErrorCode);
+			CleanupStack::PopAndDestroy(); //elementTag
+			}
+		else
+			{
+			iContentHandler->OnStartElementL(aElement, aAttributes, aErrorCode);				
+			}			
+		}
+	iCachedUris.ResetAndDestroy();
+	iCachedPrefixes.ResetAndDestroy();
+	iCachedErrors.Reset();
+}
+
+	
+/**
+This method is a callback to indicate the end of the element has been reached.
+@param				aElement is a handle to the element's details.
+@param				aErrorCode is the error code.
+					If this is not KErrNone then special action may be required.
+*/
+void CXmlEngContentHandler::OnEndElementL(const RTagInfo& aElement, TInt aErrorCode)
+{
+	_LIT8(KInclude, "Include");
+	_LIT8(KXopIncludeUri, "http://www.w3.org/2004/08/xop/include");
+	
+	if(iSkipIncludeElement)
+		{
+		if( aElement.LocalName().DesC() == KInclude
+	    	&& aElement.Uri().DesC() == KXopIncludeUri)
+			{
+			--iSkipIncludeElement;				
+			}
+		return;
+		}
+	else
+	    {
+	    iSkipPrefixMapping = EFalse;
+	    }
+
+	if(iDeserializer->IsFeatureEnabled(EConvertTagsToLowerCase))
+		{
+		RTagInfo elementTag = ConvertNameToLowerCaseL(aElement);
+		CleanupClosePushL(elementTag);
+		iContentHandler->OnEndElementL(elementTag, aErrorCode);
+		CleanupStack::PopAndDestroy(&elementTag); //elementTag
+		}
+	else
+		{
+		iContentHandler->OnEndElementL(aElement, aErrorCode);	
+		}
+}
+
+/**
+This method is a callback that sends the content of the element.
+Not all the content may be returned in one go. The data may be sent in chunks.
+When an OnEndElementL is received this means there is no more content to be sent.
+@param				aBytes is the raw content data for the element. 
+					The client is responsible for converting the data to the 
+					required character set if necessary.
+					In some instances the content may be binary and must not be converted.
+@param				aErrorCode is the error code.
+					If this is not KErrNone then special action may be required.
+*/
+void CXmlEngContentHandler::OnContentL(const TDesC8& aBytes, TInt aErrorCode)
+{
+	if(iSkipIncludeElement)
+		{
+		return;
+		}
+	iContentHandler->OnContentL(aBytes, aErrorCode);
+}
+	
+/**
+This method is a notification of the beginning of the scope of a prefix-URI Namespace mapping.
+This method is always called before the corresponding OnStartElementL method.
+@param				aPrefix is the Namespace prefix being declared.
+@param				aUri is the Namespace URI the prefix is mapped to.
+@param				aErrorCode is the error code.
+					If this is not KErrNone then special action may be required.
+*/
+void CXmlEngContentHandler::OnStartPrefixMappingL(const RString& aPrefix, const RString& aUri, 
+									   TInt aErrorCode)
+{
+	if(iSkipIncludeElement)
+		{
+		return;
+		}
+	iSkipPrefixMapping = EFalse;
+	HBufC8* pref = aPrefix.DesC().AllocL();
+	HBufC8* uri = aUri.DesC().AllocL();
+	iCachedPrefixes.AppendL(pref);
+	iCachedUris.AppendL(uri);
+	iCachedErrors.Append(aErrorCode);
+}
+
+/**
+This method is a notification of the end of the scope of a prefix-URI mapping.
+This method is called after the corresponding DoEndElementL method.
+@param				aPrefix is the Namespace prefix that was mapped.
+@param				aErrorCode is the error code.
+					If this is not KErrNone then special action may be required.
+*/
+void CXmlEngContentHandler::OnEndPrefixMappingL(const RString& aPrefix, TInt aErrorCode)
+{
+	if(iSkipPrefixMapping)
+		{
+		return;
+		}
+	iContentHandler->OnEndPrefixMappingL(aPrefix, aErrorCode);
+}
+
+/**
+This method is a notification of ignorable whitespace in element content.
+@param				aBytes are the ignored bytes from the document being parsed.
+@param				aErrorCode is the error code.
+					If this is not KErrNone then special action may be required.
+*/
+void CXmlEngContentHandler::OnIgnorableWhiteSpaceL(const TDesC8& aBytes, TInt aErrorCode)
+{
+	if(iSkipIncludeElement)
+		{
+		return;
+		}
+	iContentHandler->OnIgnorableWhiteSpaceL(aBytes, aErrorCode);
+}
+
+/**
+This method is a notification of a skipped entity. If the parser encounters an 
+external entity it does not need to expand it - it can return the entity as aName 
+for the client to deal with.
+@param				aName is the name of the skipped entity.
+@param				aErrorCode is the error code.
+					If this is not KErrNone then special action may be required.
+*/
+void CXmlEngContentHandler::OnSkippedEntityL(const RString& aName, TInt aErrorCode)
+{
+	if(iSkipIncludeElement)
+		{
+		return;
+		}
+	iContentHandler->OnSkippedEntityL(aName, aErrorCode);
+}
+
+/**
+This method is a receive notification of a processing instruction.
+@param				aTarget is the processing instruction target.
+@param				aData is the processing instruction data. If empty none was supplied.
+@param				aErrorCode is the error code.
+					If this is not KErrNone then special action may be required.
+*/
+void CXmlEngContentHandler::OnProcessingInstructionL(const TDesC8& aTarget,
+										  const TDesC8& aData, 
+										  TInt aErrorCode)
+{
+	if(iSkipIncludeElement)
+		{
+		return;
+		}
+	iContentHandler->OnProcessingInstructionL(aTarget, aData, aErrorCode);
+}
+
+/**
+This method indicates an error has occurred.
+@param				aError is the error code
+*/
+void CXmlEngContentHandler::OnError(TInt aErrorCode)
+{
+	iContentHandler->OnError(aErrorCode);	
+}
+
+/**
+This method obtains the interface matching the specified uid.
+@return				0 if no interface matching the uid is found.
+					Otherwise, the this pointer cast to that interface.
+@param				aUid the uid identifying the required interface.
+*/
+TAny* CXmlEngContentHandler::GetExtendedInterface(const TInt32 /*aUid*/)
+{
+	return 0;	
+}
+
+/**
+This method strips CID string from "cid:" prefix to fetch the pure CID value
+@return				CID value
+@param				aCid CID string
+*/
+TPtrC8 CXmlEngContentHandler::CidValue(const TDesC8& aCid)
+	{
+	_LIT8(KCidPrefix, "cid:*");
+	TInt position = aCid.Match(KCidPrefix);
+	if(position < 0)
+		{
+		position = 0;
+		}
+	return aCid.Mid( position + KCidPrefix().Size() - 1); // minus star character (*)
+	}
+
+/**
+This method converts element name to lower case and creates new tag info
+@return				New tag info with lower case element name
+@param				aTagInfo Original tag info
+*/
+RTagInfo CXmlEngContentHandler::ConvertNameToLowerCaseL(const RTagInfo& aElement)
+	{
+	// convert name to lower case, create new RTagInfo, invoke callback
+	HBufC8* uriBuf = aElement.Uri().DesC().AllocLC();
+	HBufC8* prefBuf = aElement.Prefix().DesC().AllocLC();
+	HBufC8* nameBuf = aElement.LocalName().DesC().AllocLC();
+	nameBuf->Des().LowerCase();
+	
+	RString uri = iStrPool.OpenStringL(uriBuf->Des());
+	CleanupClosePushL(uri);
+	RString pref = iStrPool.OpenStringL(prefBuf->Des());
+	CleanupClosePushL(pref);
+	RString name = iStrPool.OpenStringL(nameBuf->Des());
+	CleanupStack::Pop(&pref);
+	CleanupStack::Pop(&uri);
+	CleanupStack::PopAndDestroy(nameBuf);
+	CleanupStack::PopAndDestroy(prefBuf);
+	CleanupStack::PopAndDestroy(uriBuf);
+	RTagInfo elementTag;
+	elementTag.Open(uri, pref, name);
+	TPtrC8 a = elementTag.LocalName().DesC();
+	return elementTag;	
+	}