blob: d0946c859c1673db459a7b9fc27009cb9999b137 [file] [log] [blame]
/*******************************************************************************
* 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);
}
}
}
}