applayerprotocols/wappushsupport/XmlLib/XmlValid.cpp
changeset 0 b16258d2340f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/applayerprotocols/wappushsupport/XmlLib/XmlValid.cpp	Tue Feb 02 01:09:52 2010 +0200
@@ -0,0 +1,595 @@
+// Copyright (c) 2000-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:
+//
+
+// Local includes
+//
+#include "XmlValid.h"
+
+// System includes
+//
+#include <cdtdmodel.h>
+#include <xmlelemt.h>
+#include <cbnfnode.h>
+#include <cnodeleteattribute.h>
+#include <xmllib.h>
+
+
+CXmlValidator::CXmlValidator(CBNFNode& aDTD, CAttributeLookupTable& aALUT) : iDTD(aDTD), iALUT(aALUT)
+	{
+	}
+
+CXmlValidator::~CXmlValidator()
+	{
+	delete iCounterArray;
+	}
+
+CXmlValidator* CXmlValidator::NewL(CBNFNode& aDTD, CAttributeLookupTable& aALUT)
+	{
+	CXmlValidator* self = new(ELeave) CXmlValidator(aDTD, aALUT);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return(self);
+	}
+
+void CXmlValidator::ConstructL()
+	{
+	iCounterArray = new(ELeave) CArrayFixFlat<TInt>(3);
+	}
+
+TInt CXmlValidator::ValidateTreeL(CXmlElement* aRootNode)
+	{
+	if( aRootNode == NULL )
+		{
+		return( EWapErrXmlLibMissingDocument );
+		}
+	CNode* currentNode = aRootNode;
+	CNode* childNode = NULL;
+	TInt returnCode = KErrNone;
+
+	FOREVER		// Hihi :)
+		{
+		if( childNode == NULL )
+			{
+			// We entered this node first time, going down the tree
+
+			returnCode = ValidateNodeL((CXmlElement*)currentNode);
+			if( returnCode != KErrNone )
+				{
+				return( returnCode );
+				}
+
+			childNode = currentNode->NextChild();  // The first born...
+			}
+		else
+			{
+			// We returned from a child node
+			childNode = currentNode->NextChild(childNode);
+			}
+
+		if( childNode == NULL )
+			{
+			if( currentNode == aRootNode )
+				{
+				// The tree is done.
+				return( KErrNone );
+				}
+			// Go up the tree
+			childNode = currentNode;
+			currentNode = currentNode->Parent();
+			}
+		else
+			{
+			currentNode = childNode;
+			childNode = NULL;
+			}
+		}
+	}
+
+TInt CXmlValidator::ValidateNodeL(CXmlElement* aNode)
+	{
+	TInt returnCode = KErrNone;
+
+	CBNFNode* dtdNode = REINTERPRET_CAST(CBNFNode*,iDTD.Attribute((const TDesC*)(aNode->Type())));
+	if( dtdNode == NULL )
+		{
+		return( EWapErrXmlLibIllegalTagName );
+		}
+	returnCode = ValidateNodeAttributesL(aNode, dtdNode);
+	if( returnCode == KErrNone )
+		{
+		returnCode = ValidateNodeChildrenL(aNode, dtdNode);
+		}
+
+	// Here we could perform the validation of Node's data
+
+	return( returnCode );
+	}
+
+
+TInt CXmlValidator::ValidateNodeChildrenL(CXmlElement* aDocumentNode, CBNFNode* aDTDNode)
+	{
+	iCurrentDocumentChild = (CXmlElement*)aDocumentNode->NextChild();
+	if( iCurrentDocumentChild != NULL && iDTD.Attribute((const TDesC*)(iCurrentDocumentChild->Type())) == NULL )
+		{
+		return( EWapErrXmlLibIllegalTagName );
+		}
+
+	TInt returnValue = KErrNone;
+	TBool nodeFinished = EFalse;
+	iDTDChildNode = NULL;
+	CBNFNode* dtdNode;
+	iDTDNodeStack.Clear();
+	iDTDNodeStack.PushL(aDTDNode);
+	iCounterArray->Reset();
+	iNodeMatched = EFalse;
+	while( iCurrentDocumentChild != NULL && !iDTDNodeStack.IsEmpty() )
+		{
+		dtdNode = iDTDNodeStack.Head();
+		nodeFinished = EFalse;
+		switch(dtdNode->Type())
+			{
+		case EReference:
+			returnValue = HandleReferenceL(dtdNode, nodeFinished);
+			break;
+		case ERoot:
+		case EAnd:
+			returnValue = HandleAndL(dtdNode, nodeFinished);
+			break;
+		case EOr:
+			returnValue = HandleOrL(dtdNode, nodeFinished);
+			break;
+		case EOptional:
+			returnValue = HandleOptionalL(dtdNode, nodeFinished);
+			break;
+		case ENMore:
+			returnValue = HandleNMoreL(dtdNode, nodeFinished);
+			break;
+		case EIncomplete:
+			nodeFinished = ETrue;
+			iNodeMatched = ETrue;
+			break;
+			}
+
+		if( returnValue != KErrNone )
+			{
+			return( returnValue );
+			}
+
+		if( nodeFinished )
+			{
+			iDTDChildNode = dtdNode;
+			iDTDNodeStack.Pop();
+			}
+		else
+			{
+			iDTDChildNode = NULL;
+			}
+
+		if( iNodeMatched )
+			{
+			iCurrentDocumentChild = (CXmlElement*)aDocumentNode->NextChild(iCurrentDocumentChild);
+			if( iCurrentDocumentChild != NULL && iDTD.Attribute((const TDesC*)(iCurrentDocumentChild->Type())) == NULL )
+				{
+				return( EWapErrXmlLibIllegalTagName );
+				}
+			iNodeMatched = EFalse;
+			iSubNodeMatch = EMatch;
+			}
+		}
+
+	if( iCurrentDocumentChild == NULL )
+		{
+		return( KErrNone );
+		}
+	else
+		{
+		return( EWapErrXmlLibInvalidDocumentStructure );
+		}
+	}
+
+TInt CXmlValidator::HandleReferenceL(CBNFNode* aDTDNode, TBool& aNodeFinished)
+	{	
+	if( iDTDChildNode == NULL )
+		{
+		CNoDeleteAttributeT<CBNFNode*>* attributeNode = REINTERPRET_CAST(CNoDeleteAttributeT<CBNFNode*>*, aDTDNode->Attribute(CBNFNode::KReference()));
+		CBNFNode* referencedNode = attributeNode->Attribute();
+
+		const TDesC* dtdNodeName = NodeName(referencedNode);
+		if( (*dtdNodeName)[0] != '%' )
+			{
+			aNodeFinished = ETrue;
+			if( iCurrentDocumentChild->Type()->Compare(*dtdNodeName) == 0 || 
+				( iCurrentDocumentChild->Type()->Compare(KCDataID) == 0 && 
+				  dtdNodeName->Compare(KPCDataID) == 0 )
+			  )
+				{
+				iNodeMatched = ETrue;
+				}
+			else
+				{
+				iNodeMatched = EFalse;
+				}
+			}
+		else
+			{
+			aNodeFinished = EFalse;
+			iDTDNodeStack.PushL(referencedNode);
+			}
+		}
+	else
+		{
+		aNodeFinished = ETrue;
+		}
+	return( KErrNone );
+	}
+
+TInt CXmlValidator::HandleAndL(CBNFNode* aDTDNode, TBool& aNodeFinished)
+	{
+	if( iDTDChildNode == NULL )
+		{
+		iSubNodeMatch = EMiss;
+		aNodeFinished = EFalse;
+		iDTDNodeStack.PushL((CBNFNode*)aDTDNode->NextChild());
+		iCounterArray->InsertL(0, 0);
+		}
+	else
+		{
+		if( (iSubNodeMatch == EMatch || iSubNodeMatch == EConditionalMiss) && aDTDNode->NextChild(iDTDChildNode)!=NULL )
+			{
+			if( iSubNodeMatch == EMatch )
+				{
+				(*iCounterArray)[0]++;
+				}
+			aNodeFinished = EFalse;
+			iSubNodeMatch = EMiss;
+			iDTDNodeStack.PushL( (CBNFNode*)aDTDNode->NextChild(iDTDChildNode) );
+			}
+		else
+			{
+			if( iCounterArray->At(0) > 0 && iSubNodeMatch == EConditionalMiss )
+				iSubNodeMatch = EMatch;
+			aNodeFinished = ETrue;
+			iCounterArray->Delete(0);
+			}
+		}
+	return( KErrNone );
+	}
+
+TInt CXmlValidator::HandleOrL(CBNFNode* aDTDNode, TBool& aNodeFinished)
+	{
+	if( iDTDChildNode == NULL )
+		{
+		aNodeFinished = EFalse;
+		iSubNodeMatch = EMiss;
+		iDTDNodeStack.PushL((CBNFNode*)aDTDNode->NextChild());
+		iDocumentChildMarkStack.PushL(iCurrentDocumentChild);
+		}
+	else
+		{
+		if( (iSubNodeMatch == EMiss || iSubNodeMatch == EConditionalMiss) && aDTDNode->NextChild(iDTDChildNode)!=NULL )
+			{
+			aNodeFinished = EFalse;
+			iDTDNodeStack.PushL((CBNFNode*)aDTDNode->NextChild(iDTDChildNode) );
+			iCurrentDocumentChild = iDocumentChildMarkStack.Head();
+			}
+		else
+			{
+			if( iSubNodeMatch != EMatch )
+				{
+				iCurrentDocumentChild = iDocumentChildMarkStack.Pop();
+				}
+			else
+				{
+				iDocumentChildMarkStack.Pop();
+				}
+
+			aNodeFinished = ETrue;
+			}
+		}
+	return( KErrNone );
+	}
+
+TInt CXmlValidator::HandleOptionalL(CBNFNode* aDTDNode, TBool& aNodeFinished)
+	{
+	if( iDTDChildNode == NULL )
+		{
+		aNodeFinished = EFalse;
+		iDTDNodeStack.PushL((CBNFNode*)aDTDNode->NextChild());
+		}
+	else
+		{
+		aNodeFinished = ETrue;
+		if( iSubNodeMatch == EMiss )
+			{
+			iSubNodeMatch = EConditionalMiss;
+			}
+		}
+	return( KErrNone );
+	}
+
+TInt CXmlValidator::HandleNMoreL(CBNFNode* aDTDNode, TBool& aNodeFinished)
+	{
+	if( iDTDChildNode == NULL )
+		{
+		iSubNodeMatch = EMiss;
+		iDTDNodeStack.PushL((CBNFNode*)aDTDNode->NextChild());
+		iCounterArray->InsertL(0, 0);
+		aNodeFinished = EFalse;
+		}
+	else
+		{
+		if( iSubNodeMatch == EMatch )
+			{
+			(*iCounterArray)[0]++;
+			iDTDNodeStack.PushL((CBNFNode*)aDTDNode->NextChild());
+			iSubNodeMatch = EMiss;
+			aNodeFinished = EFalse;
+			}
+		else
+			{
+			aNodeFinished = ETrue;
+			if( iCounterArray->At(0) > 0 )
+				{
+				iSubNodeMatch = EMatch;
+				}
+			else if( aDTDNode->AttributeExists(CBNFNode::KNMoreMinimum()) )
+				{
+				iSubNodeMatch = EMiss;
+				}
+			else
+				{
+				iSubNodeMatch = EConditionalMiss;
+				}
+			iCounterArray->Delete(0);
+			}
+		}
+	return( KErrNone );
+	}
+
+const TDesC*  CXmlValidator::NodeName(CBNFNode* aNode)
+    {
+	TInt count=iDTD.AttributeCount();
+	const TDesC* nodeId = NULL;
+	for (TInt i = 0; i < count; i++)
+		{
+		const TDesC* type;
+		if (aNode == iDTD.AttributeByIndex(i,type))
+			{
+			nodeId = type;
+			break;
+			}
+		}
+	return nodeId;
+    }
+
+
+TInt CXmlValidator::ValidateNodeAttributesL(CXmlElement* aDocumentNode, CBNFNode* aDTDNode)
+// aDTDNode is the node from the DTD tree corresponding to the aDocumentNode
+	{
+
+	TInt i;
+	TInt count=aDTDNode->AttributeCount();
+	for(i=0; i < count; i++)
+		{
+		const TDesC* attributeName;
+		CDTDModel::CDTDElementAttribute* DTDAttribute = REINTERPRET_CAST(CDTDModel::CDTDElementAttribute*, aDTDNode->AttributeByIndex(i,attributeName) );
+
+		if( DTDAttribute->iValueType == CDTDModel::CDTDElementAttribute::EReference )
+			{				
+			CNoDeleteAttributeT<CBNFNode*>* attributeNode = REINTERPRET_CAST(CNoDeleteAttributeT<CBNFNode*>*,DTDAttribute->iType->Attribute(CBNFNode::KReference()));
+			TInt refReturnValue = ValidateNodeAttributesL(aDocumentNode, attributeNode->Attribute());
+			if( refReturnValue != KErrNone )
+				{
+				return(refReturnValue);
+				}
+			continue;
+			}
+
+//		const TDesC* attributeName = aDTDNode->AttributeTypeByIndex(i);
+		const TDesC* documentAttributeValue = aDocumentNode->Attribute(*attributeName);
+		if( documentAttributeValue != NULL )
+			{
+			if( DTDAttribute->iValueType == CDTDModel::CDTDElementAttribute::EFixed )
+				{
+				if( documentAttributeValue->Compare(*(DTDAttribute->iValue->Data()) ) != 0 )
+					{
+					return( EWapErrXmlLibIllegalFixedAttributeValue );
+					}
+				}
+			else
+				{
+				TPtr attrPtr(((HBufC*)documentAttributeValue)->Des());
+				TInt errorCode = NormalizeAndCheckAttributeValueL(attrPtr, DTDAttribute->iType);
+				if( errorCode != KErrNone )
+					{
+					return( errorCode );
+					}
+				}
+			}
+		else
+			{
+			switch( DTDAttribute->iValueType )
+				{
+			case CDTDModel::CDTDElementAttribute::ERequired:
+				{
+				return( EWapErrXmlLibMissingRequiredAttribute );
+				} // break;
+			case CDTDModel::CDTDElementAttribute::EFixed:
+			case CDTDModel::CDTDElementAttribute::EDefault:
+				aDocumentNode->SetAttributeL( *attributeName, *(DTDAttribute->iValue->Data()), iALUT);
+				break;
+			case CDTDModel::CDTDElementAttribute::EImplied:
+			default:
+				break;
+				}
+			}
+		}
+	return(KErrNone);
+	}
+
+
+TInt CXmlValidator::NormalizeAndCheckAttributeValueL(TPtr& aAttributeValue, CBNFNode* aAttributeValueTypeRoot)
+	{
+	NormalizeAttributeValueWhiteSpaces(aAttributeValue);
+
+	TInt returnValue = KErrNone;
+	TBool nodeFinished = EFalse;
+	iDTDChildNode = NULL;
+	CBNFNode* dtdNode;
+	iDTDNodeStack.Clear();
+	iDTDNodeStack.PushL(aAttributeValueTypeRoot);
+	iCounterArray->Reset();
+	iNodeMatched = EFalse;
+	while( !iNodeMatched && !iDTDNodeStack.IsEmpty() )
+		{
+		dtdNode = iDTDNodeStack.Head();
+		nodeFinished = EFalse;
+		switch(dtdNode->Type())
+			{
+		case EReference:
+			returnValue = HandleReferenceInAttributeValueTypeL(dtdNode, nodeFinished);
+			break;
+		case ERoot:
+		case EAnd:
+			returnValue = HandleAndL(dtdNode, nodeFinished);
+			break;
+		case EOr:
+			returnValue = HandleOrL(dtdNode, nodeFinished);
+			break;
+		case EOptional:
+			returnValue = HandleOptionalL(dtdNode, nodeFinished);
+			break;
+		case ENMore:
+			returnValue = HandleNMoreL(dtdNode, nodeFinished);
+			break;
+		case EIncomplete:
+			nodeFinished = ETrue;
+			returnValue = HandleAttributeValueCheckAndNormalize( aAttributeValue, NodeName(dtdNode) );
+			break;
+			}
+
+		if( returnValue != KErrNone )
+			{
+			return( returnValue );
+			}
+
+		if( nodeFinished )
+			{
+			iDTDChildNode = dtdNode;
+			iDTDNodeStack.Pop();
+			}
+		else
+			{
+			iDTDChildNode = NULL;
+			}
+		}
+
+	if( iNodeMatched )
+		{
+		return( KErrNone );
+		}
+	else
+		{
+		return( EWapErrXmlLibIllegalAttributeValue );
+		}
+	}
+
+TInt CXmlValidator::HandleReferenceInAttributeValueTypeL(CBNFNode* aDTDNode, TBool& aNodeFinished)
+	{
+	if( iDTDChildNode == NULL )
+		{
+		CNoDeleteAttributeT<CBNFNode*>* attributeNode = REINTERPRET_CAST(CNoDeleteAttributeT<CBNFNode*>*, aDTDNode->Attribute(CBNFNode::KReference()));
+		CBNFNode* referencedNode = attributeNode->Attribute();
+		aNodeFinished = EFalse;
+		iDTDNodeStack.PushL(referencedNode);
+		}
+	else
+		{
+		aNodeFinished = ETrue;
+		}
+	return( KErrNone );
+	}
+
+TInt CXmlValidator::HandleAttributeValueCheckAndNormalize(TPtr& aAttributeValue, const TDesC* aAttributeValueType)
+	{
+	_LIT( KNMTOKENID, "NMTOKEN");
+	_LIT( KIDID, "ID" );
+
+	if( aAttributeValueType->Compare(KCDataID) != 0 )
+		{
+		// Xml specs 3.3.3, when declared calue is not CDATA, leading and trailing spaces
+		// are wasted and space sequences are replaced with single space
+		aAttributeValue.TrimAll();
+		}
+	else
+		{
+		// The value type is CDATA
+		// In future, here we could ran a check for the contents the attribute that it
+		// corresponds to CDATA constraints
+		iNodeMatched = ETrue;
+		return( KErrNone );
+		}
+
+	if( aAttributeValueType->Compare(KNMTOKENID) == 0 )
+		{
+		// Here we could ran a check for the attribute contents to correspond
+		// to NMTOKEN rules
+		iNodeMatched = ETrue;
+		}
+	else if( aAttributeValueType->Compare(KIDID) == 0 )
+		{
+		// Here we could ran a check for the attribute contents to correspond
+		// to ID rules
+		iNodeMatched = ETrue;
+		}
+	else
+		{
+		// The value aAttributeValueType contains an enumerated value. Check if this one matches to the attribute value
+		if( aAttributeValue.Compare(*aAttributeValueType) == 0 )
+			{
+			iNodeMatched = ETrue;
+			}
+		else
+			{
+			iNodeMatched = EFalse;
+			}
+		}
+
+	return( KErrNone );
+	}
+
+void CXmlValidator::NormalizeAttributeValueWhiteSpaces(TPtr& aAttributeValue)
+	{
+	// White space normalization, XML specs 3.3.3
+	TInt i;
+	TInt length=aAttributeValue.Length();
+	TText* stringPtr=(TText*)aAttributeValue.Ptr();
+	for(i=0; i < length; i++)
+		{
+		TText ch=*stringPtr;
+		if( ch==0xD && i<length-1 && *(stringPtr+1)==0xA)
+			{
+			aAttributeValue.Delete(i,1);
+			*stringPtr=0x20;
+			length--;
+			}
+		if(	ch==0x9 || ch==0xA || ch==0xD)
+			{
+			*stringPtr = 0x20;
+			}
+		++stringPtr;
+		}
+	}