--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/messagingappbase/smilparser/SMILdtd/SRC/Smildtd.cpp Thu Dec 17 08:44:11 2009 +0200
@@ -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 "smildtdenum.h"
+#endif
+#include <smildtd.h>
+#include "SmilData.h"
+#include <stringpool.h>
+#include "smilelements.h"
+#include "smilattributes.h"
+#include "smilgenericelements.h"
+#include <gmxmlconstants.h>
+
+//
+// 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<aChildElements.Count(); i++)
+ {
+ // Check for the 'empty tag'. We could take a local copy but that would
+ // not be most efficient so we have slightly more complex code.
+
+ {
+ // Given a current state and tag, find a valid transition.
+ // Use a binary search - the array is sorted on tag name first and then
+ // from state. We binary chop to a suitable level and then do a linear
+ // search until we hit pay-dirt or find an element which proves. We
+ // only bother to binary search based on the tag name.
+ // This is a home baked binary chop and could potentially be made more elegant.
+
+ tranArrInd = midPoint;
+ TInt jump = initJump;
+ TBool keepChopping = true;
+ TInt compVal;
+ TPtrC tranTag;
+ while(keepChopping)
+ {
+ tranTag.Set( aStateTrans[tranArrInd].TagName, aStateTrans[tranArrInd].TagLength);
+
+ compVal = aChildElements[i].Compare(tranTag);
+ if(compVal < 0)
+ {
+ tranArrInd -= jump;
+ }
+ else if(compVal > 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;
+
+ }