/******************************************************************************* | |
* Copyright (c) 2008 Standards for Technology in Automotive Retail | |
* 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 | |
* http://www.eclipse.org/legal/epl-v10.html | |
* | |
* Contributors: | |
* David Carver - STAR - bug 224197 - initial API and implementation | |
* based on work from Apache Xalan 2.7.0 | |
*******************************************************************************/ | |
/* | |
* Copyright 1999-2004 The Apache Software Foundation. | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
/* | |
* $Id: StackGuard.java,v 1.2 2008/03/28 02:38:16 dacarver Exp $ | |
*/ | |
package org.eclipse.wst.xsl.core.internal.compiler.xslt10.transformer; | |
import javax.xml.transform.TransformerException; | |
import org.apache.xalan.res.XSLMessages; | |
import org.apache.xalan.templates.Constants; | |
import org.apache.xalan.templates.ElemTemplate; | |
import org.apache.xalan.templates.ElemTemplateElement; | |
import org.apache.xml.utils.ObjectStack; | |
/** | |
* Class to guard against recursion getting too deep. | |
*/ | |
public class StackGuard { | |
/** | |
* Used for infinite loop check. If the value is -1, do not check for | |
* infinite loops. Anyone who wants to enable that check should change the | |
* value of this variable to be the level of recursion that they want to | |
* check. Be careful setting this variable, if the number is too low, it may | |
* report an infinite loop situation, when there is none. Post version | |
* 1.0.0, we'll make this a runtime feature. | |
*/ | |
private int m_recursionLimit = -1; | |
protected TransformerImpl m_transformer; | |
/** | |
* Get the recursion limit. Used for infinite loop check. If the value is | |
* -1, do not check for infinite loops. Anyone who wants to enable that | |
* check should change the value of this variable to be the level of | |
* recursion that they want to check. Be careful setting this variable, if | |
* the number is too low, it may report an infinite loop situation, when | |
* there is none. Post version 1.0.0, we'll make this a runtime feature. | |
* | |
* @return The recursion limit. | |
*/ | |
public int getRecursionLimit() { | |
return m_recursionLimit; | |
} | |
/** | |
* Set the recursion limit. Used for infinite loop check. If the value is | |
* -1, do not check for infinite loops. Anyone who wants to enable that | |
* check should change the value of this variable to be the level of | |
* recursion that they want to check. Be careful setting this variable, if | |
* the number is too low, it may report an infinite loop situation, when | |
* there is none. Post version 1.0.0, we'll make this a runtime feature. | |
* | |
* @param limit | |
* The recursion limit. | |
*/ | |
public void setRecursionLimit(int limit) { | |
m_recursionLimit = limit; | |
} | |
/** | |
* Constructor StackGuard | |
* | |
*/ | |
public StackGuard(TransformerImpl transformerImpl) { | |
m_transformer = transformerImpl; | |
} | |
/** | |
* Overide equal method for StackGuard objects | |
* | |
*/ | |
public int countLikeTemplates(ElemTemplate templ, int pos) { | |
ObjectStack elems = m_transformer.getCurrentTemplateElements(); | |
int count = 1; | |
for (int i = pos - 1; i >= 0; i--) { | |
if ((ElemTemplateElement) elems.elementAt(i) == templ) | |
count++; | |
} | |
return count; | |
} | |
/** | |
* Get the next named or match template down from and including the given | |
* position. | |
* | |
* @param pos | |
* the current index position in the stack. | |
* @return null if no matched or named template found, otherwise the next | |
* named or matched template at or below the position. | |
*/ | |
private ElemTemplate getNextMatchOrNamedTemplate(int pos) { | |
ObjectStack elems = m_transformer.getCurrentTemplateElements(); | |
for (int i = pos; i >= 0; i--) { | |
ElemTemplateElement elem = (ElemTemplateElement) elems.elementAt(i); | |
if (null != elem) { | |
if (elem.getXSLToken() == Constants.ELEMNAME_TEMPLATE) { | |
return (ElemTemplate) elem; | |
} | |
} | |
} | |
return null; | |
} | |
/** | |
* Check if we are in an infinite loop | |
* | |
* @throws TransformerException | |
*/ | |
public void checkForInfinateLoop() throws TransformerException { | |
int nTemplates = m_transformer.getCurrentTemplateElementsCount(); | |
if (nTemplates < m_recursionLimit) | |
return; | |
if (m_recursionLimit <= 0) | |
return; // Safety check. | |
// loop from the top index down to the recursion limit (I don't think | |
// there's any need to go below that). | |
for (int i = (nTemplates - 1); i >= m_recursionLimit; i--) { | |
ElemTemplate template = getNextMatchOrNamedTemplate(i); | |
if (null == template) | |
break; | |
int loopCount = countLikeTemplates(template, i); | |
if (loopCount >= m_recursionLimit) { | |
// throw new TransformerException("Template nesting too deep. | |
// nesting = "+loopCount+ | |
// ", template "+((null == template.getName()) ? "name = " : | |
// "match = ")+ | |
// ((null != template.getName()) ? template.getName().toString() | |
// : template.getMatch().getPatternString())); | |
String idIs = XSLMessages.createMessage(((null != template | |
.getName()) ? "nameIs" : "matchPatternIs"), null); | |
Object[] msgArgs = new Object[] { | |
new Integer(loopCount), | |
idIs, | |
((null != template.getName()) ? template.getName() | |
.toString() : template.getMatch() | |
.getPatternString()) }; | |
String msg = XSLMessages.createMessage("recursionTooDeep", | |
msgArgs); | |
throw new TransformerException(msg); | |
} | |
} | |
} | |
} |