/* * 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.14 2005/01/23 00:37:17 mcnamara Exp $ */ package org.apache.xalan.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; 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 javax.xml.transform.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); } } } }