[294896] Content model validation utility fails to handle large size documents
diff --git a/bundles/org.eclipse.wst.xml.core/src-contentmodel/org/eclipse/wst/xml/core/internal/contentmodel/internal/util/CMValidator.java b/bundles/org.eclipse.wst.xml.core/src-contentmodel/org/eclipse/wst/xml/core/internal/contentmodel/internal/util/CMValidator.java index 3ee535f..5735bc3 100644 --- a/bundles/org.eclipse.wst.xml.core/src-contentmodel/org/eclipse/wst/xml/core/internal/contentmodel/internal/util/CMValidator.java +++ b/bundles/org.eclipse.wst.xml.core/src-contentmodel/org/eclipse/wst/xml/core/internal/contentmodel/internal/util/CMValidator.java
@@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2002, 2006 IBM Corporation and others. + * Copyright (c) 2002, 2009 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -18,6 +18,7 @@ import java.util.Hashtable; import java.util.Iterator; import java.util.List; +import java.util.Stack; import java.util.Vector; import org.eclipse.wst.xml.core.internal.contentmodel.CMAnyElement; import org.eclipse.wst.xml.core.internal.contentmodel.CMContent; @@ -307,59 +308,69 @@ } - public void validateElementList(ElementList list, GraphNode node, ElementContentComparator comparator, Result result, boolean loopFlag) - { - //println("+validateElementList " + node + " " + list); - if (list == null && node.isTerminal) - { - result.isValid = true; - } - else - { - for (Iterator i = node.arcList.iterator(); i.hasNext();) - { - Arc arc = (Arc)i.next(); - boolean traverseArc = false; - if (arc.kind == Arc.ELEMENT) - { - if (list != null && comparator.matches(list.head, arc.cmNode)) - { - loopFlag = false; - traverseArc = true; - list = list.tail; // increment our position in the list - } - } - else if (arc.kind == Arc.REPEAT) - { - if (!loopFlag) - { - traverseArc = true; - } - loopFlag = true; - } - else - { - traverseArc = true; - } + public void validateElementList(ElementList initialList, GraphNode initialGraphNode, ElementContentComparator comparator, Result result, boolean initialLoopFlag) { + Stack arcStack = new Stack(); + arcStack.push(new ArcStackItem(null, false)); + boolean loopFlag = initialLoopFlag; + ElementList elementList = initialList; + GraphNode graphNode = initialGraphNode; + while(!arcStack.isEmpty() && !result.isValid) { + ArcStackItem stackElement = (ArcStackItem) arcStack.peek(); + if(stackElement.isVisited) { + arcStack.pop(); + if(stackElement.arc != null) { + result.pop(stackElement.arc); + continue; + } + } else { + stackElement.isVisited = true; + result.push(stackElement.arc); + graphNode = stackElement.arc.node; + loopFlag = stackElement.loopFlag; + } + if(elementList == null && graphNode.isTerminal) { + result.isValid = true; + } else { + for(Iterator arcIterator = graphNode.arcList.iterator(); arcIterator.hasNext();) { + Arc arc = (Arc)arcIterator.next(); + boolean traverseArc = false; + if (arc.kind == Arc.ELEMENT) { + if(elementList != null && comparator.matches(elementList.head, arc.cmNode)) { + loopFlag = false; + traverseArc = true; + elementList = elementList.tail; // increment our position in the list + } + } else if(arc.kind == Arc.REPEAT) { + if(!loopFlag) { + traverseArc = true; + } + loopFlag = true; + } else { + traverseArc = true; + } + if(traverseArc) { + if (result.canPush(arc)) { // test to see if we can push this arc due to facet constraints + arcStack.push(new ArcStackItem(arc, loopFlag)); + } + } + } + } + } + } + + + private class ArcStackItem { + + Arc arc; + boolean loopFlag; + boolean isVisited; + + public ArcStackItem(Arc arc, boolean loopflag) { + this.arc = arc; + this.loopFlag = loopflag; + this.isVisited = arc == null; + } - if (traverseArc) - { - // test to see if we can push this arc due to facet constraints - // - if (result.canPush(arc)) - { - // see if this arc leads to a correct solution - result.push(arc); - validateElementList(list, arc.node, comparator, result, loopFlag); - if (result.isValid) - { - break; - } - result.pop(arc); - } - } - } - } } @@ -416,10 +427,6 @@ ElementList elementList = createElementList(contentType, elementContent, comparator, result); if (result.isValid == true) { - // defect 226213 ... elements with a large number of children will cause the recursion based validation - // algorithm to stack overflow ... as a quick fix assume any element with a large number of children is valid - if (elementContent.size() < 500) - { boolean isGraphValidationNeeded = !(elementList == null && contentType == CMElementDeclaration.MIXED); // exlicity handle 'All' groups @@ -443,7 +450,6 @@ GraphNode node = lookupOrCreateGraph(ed); validateElementList(elementList, node, comparator, result, false); } - } } } else if (contentType == CMElementDeclaration.PCDATA)