diff -r 417699dc19c9 -r c7e9f1c97567 xml/legacyminidomparser/xmlparser/test/t_Smildtd.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xml/legacyminidomparser/xmlparser/test/t_Smildtd.cpp Mon Sep 13 13:16:40 2010 +0530 @@ -0,0 +1,549 @@ +// Copyright (c) 2003-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: +// CSMILDTD.cpp +// @file +// This file contains the definition of the SMILDTD class +// which describes the SMIL DTD and is responsible for validation +// of SMIL documents +// +// +#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS +#include "t_smildtdenum.h" +#endif +#include "t_SmilDtd.h" +#include "t_SmilData.h" +#include +#include "smilelements.h" +#include "smilattributes.h" +#include "smilgenericelements.h" +#include + +// +// Global functions // +// + + +EXPORT_C CSMILDtd* CSMILDtd::NewL() +// +// Two phase static factory function constructor +// @return Created CSMILDtd +// @leave can Leave due to OOM +// + { + CSMILDtd* self = NewLC(); + CleanupStack::Pop(); + return self; + } + +EXPORT_C CSMILDtd* CSMILDtd::NewLC() +// +// Two phase static factory function constructor +// @return Created CSMILDtd +// @leave can Leave due to OOM +// + { + CSMILDtd* self = new (ELeave) CSMILDtd(); + CleanupStack::PushL(self); + self->ConstructL(); + return self; + } + +void CSMILDtd::ConstructL() +// +// Second stage constructor +// @leave can Leave due to OOM +// + { + // nothing to do + } + + +CSMILDtd::CSMILDtd() + { + } + + +EXPORT_C CSMILDtd::~CSMILDtd() + { + } + +TBool CSMILDtd::IsValidElementL(const TDesC& aElement) const + { +// +// Checks to see if the element name passed in has been specified in the string table +// @param aElementName the element name to be checked +// @return ETrue if defined in the string table else EFalse +// @leave Leave due to OOM +// + + // Use the string table SMILElements to validate the element name + TBool validElement = EFalse; + + RStringPool pool; + CleanupClosePushL(pool); + pool.OpenL(SMILElements::Table); + + int numTableEntries = SMILElements::Table.iCount; + if(numTableEntries != 0) + { + // Using a binary search since the table is always sorted alphabetically by element. + + // Set us search indices to outer bounds of array + TInt left = 0; + TInt right = numTableEntries - 1; + TInt compareResult = 0; + TInt pos; + while (right >= left) + { + pos = (left + right) / 2; + + RStringF tableEntry = pool.StringF(pos, SMILElements::Table); + HBufC* buf = HBufC::NewLC(tableEntry.DesC().Length()); + buf->Des().Copy(tableEntry.DesC()); + + TLex string(*buf); + + TPtrC token = string.NextToken(); + compareResult = aElement.Compare(token); + if(compareResult == 0) + validElement = ETrue; + + CleanupStack::PopAndDestroy(buf); + + + if(compareResult == 0) + break; + else if (compareResult > 0) + left = pos + 1; + else + right = pos - 1; + } + + } + CleanupStack::PopAndDestroy(); // close pool + return validElement; + + } + +TInt CSMILDtd::IsValidAttributeForElementL(const TDesC& aElement, const TDesC& aAttribute, const TDesC& aAttributeValue) const + { +// +// Checks that both the Attribute Name & Attribute Value are valid using string tables stored in the document +// @param aAttributeName - name of attribute to be checked +// @param aAttributeValue - value of attribute to be checked +// @return KErrNone if attribute & value are valid, otherwise KErrXMLBadAttributeName or KErrXMLBadAttributeValue +// @leave Leave due to OOM +// + + + // To reduce the size of the element/attribute/value generic element names are used + // So for example 'img' and 'video' are both represented by the genericelement 'media' + // A table exists (SMILGenericElements) detailing these relationships + + // So first we see if there is a generic element name for this element + // If not then genericElementName will just be the element name passed in + HBufC* genericElementName = NULL; + + + RStringPool pool; + CleanupClosePushL(pool); + pool.OpenL(SMILGenericElements::Table); + + TInt numTableEntries = SMILGenericElements::Table.iCount; + if(numTableEntries != 0) + { + // Using a binary search since the table is always sorted alphabetically by element. + + // Set us search indices to outer bounds of array + TInt left = 0; + TInt right = numTableEntries - 1; + TInt pos; + while (right >= left) + { + pos = (left + right) / 2; + + RStringF elementAndGeneric = pool.StringF(pos, SMILGenericElements::Table); + + HBufC* buf = HBufC::NewLC(elementAndGeneric.DesC().Length()); + buf->Des().Copy(elementAndGeneric.DesC()); + TLex string(*buf); + + TPtrC token = string.NextToken(); + TInt compare = aElement.Compare(token); + + if(compare == 0) + { + // We've got a match so use the generic name + // This isn't pushed on the CleanupStack here as we need to be able to pop + // buf and pool whilst genericElementName is still in scope. It will be + // pushed once these aren't necessary. Because of this THERE MUST BE + // NOTHING THAT LEAVES UNTIL genericElementName IS PUT ONTO THE CLEANUPSTACK + genericElementName =(string.NextToken()).AllocL(); + } + + CleanupStack::PopAndDestroy(buf); //buf + + + if(compare == 0) + break; + else if (compare > 0) + left = pos + 1; + else + right = pos - 1; + } + } + + CleanupStack::PopAndDestroy(); // Close pool + + if(genericElementName != NULL) + { + CleanupStack::PushL(genericElementName); + } + else + { + // We didn't find a generic name so use the element name passed in + genericElementName = HBufC::NewLC(aElement.Length()); + genericElementName->Des().Copy(aElement); + } + + // Using the generic element name test to see if we have a valid attribute and value + + // assume the attribute name is invalid + TInt error = KErrXMLBadAttributeName; + + // retrieve the attributeValue string table + // this is of the form elementName attributeName attribValue1 attribValue2 ... + + CleanupClosePushL(pool); + pool.OpenL(SMILAttributes::Table); + + numTableEntries = SMILAttributes::Table.iCount; + if(numTableEntries != 0) + { + // Using a binary search since the table is always sorted alphabetically by element+attribute. + + // Set us search indices to outer bounds of array + TInt left = 0; + TInt right = numTableEntries - 1; + TInt compareResult = 0; + TInt pos; + while (right >= left) + { + pos = (left + right) / 2; + + RStringF tableEntry = pool.StringF(pos, SMILAttributes::Table); + HBufC* buf = HBufC::NewLC(tableEntry.DesC().Length()); + buf->Des().Copy(tableEntry.DesC()); + + TLex string(*buf); + + // Get the element name from the string table (the first token) + TPtrC token = string.NextToken(); + // Is this the element name we are interested in + compareResult = genericElementName->Compare(token); + if(compareResult == 0) + { + // we're looking at an entry in the string table for this element + // so test to see if it's the correct attribute too. + token.Set(string.NextToken()); + compareResult = aAttribute.Compare(token); + if(compareResult == 0) + { + // we've got the correct entry in the table (both element & attribute match) + // so now assume the error is an incorrect attribute value + error = KErrXMLBadAttributeValue; + + // get hold of the first valid attribure value + token.Set(string.NextToken()); + // if we don't have a list of attribute values then we can assume whatever we've got is valid + // so set the error to KErrNone + if (token.Length() == 0) + error = KErrNone; + else + { + // Cycle through all listed attribute values to see if we have a valid one + while (token.Length() != 0) + { + if (aAttributeValue.Compare(token) == 0) + { + // value of attribute is valid + error = KErrNone; + break; + } + else + token.Set(string.NextToken()); + + } + } + + } + + } + CleanupStack::PopAndDestroy(buf); // buf + if (compareResult == 0) // Matching item found + break; + else if (compareResult > 0) + left = pos + 1; + else + right = pos - 1; + } + + } + CleanupStack::PopAndDestroy(2); // pool, genericElementName + + return error; + } + +TBool CSMILDtd::AreValidChildElementsL(const TDesC& aParentElement, const CDesCArray& aChildElements) const +// Function to determine whether the parent/child relationship is valid in DTD +// @return ETrue if parent/child relationship is valid +// @param aParentElement the name of the parent element to be tested +// @param aChildElements an array of child element name to be tested +// @leave leave due to OOM +// + { + TBool retVal = EFalse; + + + + if(aParentElement == KSMILDTDElta) + { + retVal = CheckValidChildren(SMILDTDAChildStates,KSMILDTDAChildStateTranCount, aChildElements); + } + + else if( aParentElement == KSMILDTDEltDoc) + { + retVal = ETrue; + } + + + else if(aParentElement == KSMILDTDEltanimation || aParentElement == KSMILDTDEltaudio || aParentElement == KSMILDTDEltimg || aParentElement == KSMILDTDEltref + || aParentElement == KSMILDTDElttext || aParentElement == KSMILDTDElttextstream || aParentElement == KSMILDTDEltvideo) + { + retVal = CheckValidChildren(SMILDTDMediaChildStates, KSMILDTDMediaChildStateTranCount, aChildElements); + } + + else if(aParentElement == KSMILDTDEltbody) + { + retVal = CheckValidChildren(SMILDTDBodyChildStates, KSMILDTDBodyChildStateTranCount, aChildElements); + } + + else if(aParentElement == KSMILDTDElthead) + { + retVal = CheckValidChildren(SMILDTDHeadChildStates, KSMILDTDHeadChildStateTranCount, aChildElements); + } + + else if(aParentElement == KSMILDTDEltlayout) + { + retVal = CheckValidChildren(SMILDTDLayoutChildStates, KSMILDTDLayoutChildStateTranCount, aChildElements); + } + + else if(aParentElement == KSMILDTDEltpar || aParentElement == KSMILDTDEltseq) + { + retVal = CheckValidChildren(SMILDTDTimingChildStates, KSMILDTDTimingChildStateTranCount, aChildElements); + } + + else if(aParentElement == KSMILDTDEltsmil) + { + retVal = CheckValidChildren(SMILDTDSmilChildStates, KSMILDTDSmilChildStateTranCount, aChildElements); + } + + else if(aParentElement == KSMILDTDEltswitch) + { + retVal = CheckValidChildren(SMILDTDSwitchChildStates, KSMILDTDSwitchChildStateTranCount, aChildElements); + } + + return retVal; + } + + +TBool CSMILDtd::CheckValidChildren(const TSMILDTDChildStateType aStateTrans[],TInt aStateCount, const CDesCArray& aChildElements) const +// +// Checks child element ownership based on a Finite State Machine +// @param aFirstChild - pointer to first child element +// @param aStateTrans - Array of state transition elements. +// The elements must be ordered by tag name first and then starting state +// as this routine uses the ordering to drive an efficient search. +// @param aStateCount - the number of state transitions in the array +// @return true if the list of children matches the defined state machine +// + { + // This routine works by considering the allowed set of child elements as a Finite State + // Machine. When tracing through the list of children, each child encountered causes + // a state transition. The actual states are 'between' elements. The states are + // simply referred to by numbers, 0 is the starting state, the legal final state is + // state -1, other states are positive integers (the actual values have no significance, + // only the transitions and the start and end are of importance. + // When the list of children ends, a special 'empty tag' element is considered to be + // found. If this empty tag element causes a transition to the final state then the list + // has been successfully traversed. + // If, at any point, a child element is encountered which does not lead to a valid + // transition from the current state then the list is invalid. By considering the + // empty tag element to be on the end of the list we handle the requirements for valid + // completion. + // This routine is general - it just needs to be fed a set of state transitions for a specific + // element type. + + TBool returnValue = true; // We are successful until proved otherwise + if( aStateCount < 1 ) + { + returnValue = false; // Just check for a duff count + } + TInt fromState=KSMILDTDStartState; // Current state - the one we are looking for a transition from + TInt toState=KSMILDTDEndState; // State to which this tag leads us - initialised to avoid warning + TInt midPoint= aStateCount / 2; // Middle of the state array, used for binary search + TInt initJump = midPoint / 2; // Size of initial jump for binary search + TInt tranArrInd; // Index into the state transition array + + // Prime the search with the initial state and the tag for the first element + // We skip nodes which are not elements (e.g. text, comments or processing instructions) + + + for (TInt i = 0; i 0) + { + tranArrInd += jump; + } + jump = jump / 2; + if((compVal == 0) || (jump < KSMILDTDMinJump)) + { + keepChopping = false; + } + }// endwhile + // We have now finished binary chopping, either because we matched the tag or because + // We got to a small jump size. Now do a linear scan, up or down, to fimd a match. + + TBool up = true; // Direction of scan + tranTag.Set( aStateTrans[tranArrInd].TagName, aStateTrans[tranArrInd].TagLength); + compVal = aChildElements[i].Compare(tranTag); + if((compVal < 0) || + ((compVal == 0) && (fromState < aStateTrans[tranArrInd].FromState))) + { + up = false; + } + if( up ) + { + while((tranArrInd < aStateCount) && + ((compVal > 0) || + ((compVal == 0) && (fromState > aStateTrans[tranArrInd].FromState)))) + { + tranArrInd ++; + tranTag.Set( aStateTrans[tranArrInd].TagName, aStateTrans[tranArrInd].TagLength); + if(tranArrInd < aStateCount) + { + compVal = aChildElements[i].Compare(tranTag); + } + }// endwhile stepping up + } + else + { + while((tranArrInd >= 0) && + ((compVal < 0) || + ((compVal == 0) && (fromState < aStateTrans[tranArrInd].FromState)))) + { + tranArrInd --; + tranTag.Set( aStateTrans[tranArrInd].TagName, aStateTrans[tranArrInd].TagLength); + if(tranArrInd >= 0) + { + compVal = aChildElements[i].Compare(tranTag); + } + }// endwhile stepping down + } + // If we have a match, fine, else this is an illegal transition + if((tranArrInd >= 0) && (tranArrInd < aStateCount) && + (compVal == 0) && (fromState == aStateTrans[tranArrInd].FromState)) + { + toState = aStateTrans[tranArrInd].ToState; + } + else + { + returnValue = false; + break; + } + }//end else not reached end of list of children + + fromState = toState; + }// endfor + + if(returnValue) + { + tranArrInd = 0; + while((tranArrInd < aStateCount) && + (aStateTrans[tranArrInd].FromState != fromState) && + (aStateTrans[tranArrInd].TagLength == 0)) + { + tranArrInd++; + } + if((tranArrInd < aStateCount) && + (aStateTrans[tranArrInd].FromState == fromState) && + (aStateTrans[tranArrInd].TagLength == 0)) + { + toState = aStateTrans[tranArrInd].ToState ; // Better be the final state! + } + else + { + returnValue = false ; // No legal transition + } + } + + + return returnValue; + } + + + + +TBool CSMILDtd::CanElementHaveChildren(const TDesC& aElement) const +// +// Function to determine whether it is valid for a particular element to +// have children +// @param aElement the name of the element to be tested +// @return ETrue if it is valid for element to have children +// + { + TBool retVal = ETrue; + if(aElement == KSMILDTDEltanchor || aElement == KSMILDTDEltmeta || aElement == KSMILDTDEltroot_layout + || aElement == KSMILDTDEltregion || aElement == KSMILDTDEltarea || aElement == KSMILDTDEltmetadata + || aElement == KSMILDTDEltprefetch || aElement == KSMILDTDEltTrans) + retVal = EFalse; + + return retVal; + + }