diff --git a/jaxp/src/com/sun/java_cup/internal/runtime/lr_parser.java b/jaxp/src/com/sun/java_cup/internal/runtime/lr_parser.java index a94dff8892..27e78af076 100644 --- a/jaxp/src/com/sun/java_cup/internal/runtime/lr_parser.java +++ b/jaxp/src/com/sun/java_cup/internal/runtime/lr_parser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,8 @@ package com.sun.java_cup.internal.runtime; +import com.sun.org.apache.xalan.internal.xsltc.compiler.sym; +import java.util.Arrays; import java.util.Stack; /** This class implements a skeleton table driven LR parser. In general, @@ -134,9 +136,19 @@ import java.util.Stack; * @see com.sun.java_cup.internal.runtime.Symbol * @see com.sun.java_cup.internal.runtime.virtual_parse_stack * @author Frank Flannery + * + * @LastModified: Jan 2022 */ public abstract class lr_parser { + public static final int ID_GROUP = 1; + public static final int ID_OPERATOR = 2; + public static final int ID_TOTAL_OPERATOR = 3; + + private boolean isLiteral = false; + private int grpCount = 0; + private int opCount = 0; + private int totalOpCount = 0; /*-----------------------------------------------------------*/ /*--- Constructor(s) ----------------------------------------*/ @@ -355,8 +367,34 @@ public abstract class lr_parser { * the "scan with" clause. Do not recycle objects; every call to * scan() should return a fresh object. */ - public Symbol scan() throws java.lang.Exception { - return getScanner().next_token(); + public Symbol scan() throws Exception { + Symbol s = getScanner().next_token(); + + if (s.sym == sym.LPAREN) { + if (!isLiteral) { + grpCount++; + } + opCount++; // function + isLiteral = false; + } else if (contains(sym.OPERATORS, s.sym)) { + opCount++; + isLiteral = false; + } + + if (s.sym == sym.Literal || s.sym == sym.QNAME) { + isLiteral = true; + } + + return s; + } + + private boolean contains(final int[] arr, final int key) { + for(int i: arr) { + if (i == key) { + return true; + } + } + return false; } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ @@ -552,6 +590,9 @@ public abstract class lr_parser { /* do user initialization */ user_init(); + isLiteral = false; + grpCount = 0; + opCount = 0; /* get the first token */ cur_token = scan(); @@ -630,9 +671,29 @@ public abstract class lr_parser { } } } + + totalOpCount += opCount; return lhs_sym; } + /** + * Returns the count of operators in XPath expressions. + * + * @param id the ID of the count + * @return the count associated with the ID + */ + public int getCount(int id) { + switch (id) { + case ID_GROUP: + return grpCount; + case ID_OPERATOR: + return opCount; + case ID_TOTAL_OPERATOR: + return totalOpCount; + } + return 0; + } + /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Write a debugging message to System.err for the debugging version diff --git a/jaxp/src/com/sun/org/apache/xalan/internal/XalanConstants.java b/jaxp/src/com/sun/org/apache/xalan/internal/XalanConstants.java index b792c34aa0..d097013a0c 100644 --- a/jaxp/src/com/sun/org/apache/xalan/internal/XalanConstants.java +++ b/jaxp/src/com/sun/org/apache/xalan/internal/XalanConstants.java @@ -176,6 +176,21 @@ public final class XalanConstants { */ public static final String JDK_EXTENSION_CLASSLOADER = "jdk.xml.transform.extensionClassLoader"; + /** + * JDK XPath Expression group limit + */ + public static final String XPATH_GROUP_LIMIT = "jdk.xml.xpathExprGrpLimit"; + + /** + * JDK XPath Expression operators limit + */ + public static final String XPATH_OP_LIMIT = "jdk.xml.xpathExprOpLimit"; + + /** + * JDK XSL XPath limit or Total Number of Operators Permitted in an XSL Stylesheet + */ + public static final String XPATH_TOTALOP_LIMIT = "jdk.xml.xpathTotalOpLimit"; + //legacy System Properties public final static String ENTITY_EXPANSION_LIMIT = "entityExpansionLimit"; public static final String ELEMENT_ATTRIBUTE_LIMIT = "elementAttributeLimit" ; diff --git a/jaxp/src/com/sun/org/apache/xalan/internal/xsltc/compiler/Parser.java b/jaxp/src/com/sun/org/apache/xalan/internal/xsltc/compiler/Parser.java index 38ce8aec91..8e0e2ee614 100644 --- a/jaxp/src/com/sun/org/apache/xalan/internal/xsltc/compiler/Parser.java +++ b/jaxp/src/com/sun/org/apache/xalan/internal/xsltc/compiler/Parser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -27,7 +27,7 @@ import com.sun.java_cup.internal.runtime.Symbol; import com.sun.org.apache.xalan.internal.XalanConstants; import com.sun.org.apache.xalan.internal.utils.ObjectFactory; import com.sun.org.apache.xalan.internal.utils.SecuritySupport; -import com.sun.org.apache.xalan.internal.utils.XMLSecurityManager; +import jdk.xml.internal.XMLSecurityManager; import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg; import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodType; import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type; @@ -467,8 +467,10 @@ public class Parser implements Constants, ContentHandler { XMLSecurityManager securityManager = (XMLSecurityManager) _xsltc.getProperty(XalanConstants.SECURITY_MANAGER); for (XMLSecurityManager.Limit limit : XMLSecurityManager.Limit.values()) { - lastProperty = limit.apiProperty(); - reader.setProperty(lastProperty, securityManager.getLimitValueAsString(limit)); + if (limit.isSupported(XMLSecurityManager.Processor.PARSER)) { + lastProperty = limit.apiProperty(); + reader.setProperty(lastProperty, securityManager.getLimitValueAsString(limit)); + } } if (securityManager.printEntityCountInfo()) { lastProperty = XalanConstants.JDK_ENTITY_COUNT_INFO; @@ -1125,6 +1127,9 @@ public class Parser implements Constants, ContentHandler { expression, parent)); } catch (Exception e) { + if (ErrorMsg.XPATH_LIMIT.equals(e.getMessage())) { + throw new RuntimeException(ErrorMsg.XPATH_LIMIT); + } if (_xsltc.debug()) e.printStackTrace(); reportError(ERROR, new ErrorMsg(ErrorMsg.XPATH_PARSER_ERR, expression, parent)); diff --git a/jaxp/src/com/sun/org/apache/xalan/internal/xsltc/compiler/XPathParser.java b/jaxp/src/com/sun/org/apache/xalan/internal/xsltc/compiler/XPathParser.java index f33b34b29c..da5f8a316b 100644 --- a/jaxp/src/com/sun/org/apache/xalan/internal/xsltc/compiler/XPathParser.java +++ b/jaxp/src/com/sun/org/apache/xalan/internal/xsltc/compiler/XPathParser.java @@ -9,6 +9,10 @@ package com.sun.org.apache.xalan.internal.xsltc.compiler; import java.util.Stack; import java.util.Vector; import java.io.StringReader; +import com.sun.org.apache.xalan.internal.XalanConstants; +import jdk.xml.internal.XMLLimitAnalyzer; +import jdk.xml.internal.XMLSecurityManager; +import jdk.xml.internal.XMLSecurityManager.Limit; import com.sun.java_cup.internal.runtime.*; import com.sun.org.apache.xml.internal.dtm.DTM; import com.sun.org.apache.xalan.internal.xsltc.DOM; @@ -19,6 +23,9 @@ import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg; /** CUP v0.10j generated parser. */ public class XPathParser extends com.sun.java_cup.internal.runtime.lr_parser { + private int grpLimit = 0; + private int opLimit = 0; + private int totalOpLimit = 0; /** Default constructor. */ public XPathParser() {super();} @@ -885,10 +892,19 @@ public class XPathParser extends com.sun.java_cup.internal.runtime.lr_parser { */ public SymbolTable _symbolTable; + private XMLSecurityManager _xmlSM; + private XMLLimitAnalyzer _limitAnalyzer = null; + public XPathParser(Parser parser) { _parser = parser; _xsltc = parser.getXSLTC(); _symbolTable = parser.getSymbolTable(); + _xmlSM = (XMLSecurityManager)_xsltc.getProperty(XalanConstants.SECURITY_MANAGER); + _limitAnalyzer = new XMLLimitAnalyzer(); + // no limits if _xmlSM is null + grpLimit = (_xmlSM != null) ? _xmlSM.getLimit(Limit.XPATH_GROUP_LIMIT) : 0; + opLimit = (_xmlSM != null) ? _xmlSM.getLimit(Limit.XPATH_OP_LIMIT) : 0; + totalOpLimit = (_xmlSM != null) ? _xmlSM.getLimit(Limit.XPATH_TOTALOP_LIMIT) : 0; } public int getLineNumber() { @@ -1043,7 +1059,32 @@ public class XPathParser extends com.sun.java_cup.internal.runtime.lr_parser { try { _expression = expression; _lineNumber = lineNumber; - return super.parse(); + Symbol s = super.parse(); + int grpCount = getCount(ID_GROUP); + int opCount = getCount(ID_OPERATOR); + int totalOpCount = getCount(ID_TOTAL_OPERATOR); + + String errCode = null; + Object[] params = null; + if (grpLimit > 0 && grpCount > grpLimit) { + errCode = ErrorMsg.XPATH_GROUP_LIMIT; + params = new Object[]{grpCount, grpLimit, + _xmlSM.getStateLiteral(Limit.XPATH_GROUP_LIMIT)}; + } else if (opLimit > 0 && opCount > opLimit) { + errCode = ErrorMsg.XPATH_OPERATOR_LIMIT; + params = new Object[]{opCount, opLimit, + _xmlSM.getStateLiteral(Limit.XPATH_OP_LIMIT)}; + } else if (totalOpLimit > 0 && totalOpCount > totalOpLimit) { + errCode = ErrorMsg.XPATH_TOTAL_OPERATOR_LIMIT; + params = new Object[]{totalOpCount, totalOpLimit, + _xmlSM.getStateLiteral(Limit.XPATH_TOTALOP_LIMIT)}; + } + if (errCode != null) { + _parser.reportError(Constants.FATAL, + new ErrorMsg(errCode, lineNumber, params)); + throw new RuntimeException(ErrorMsg.XPATH_LIMIT); + } + return s; } catch (IllegalCharException e) { ErrorMsg err = new ErrorMsg(ErrorMsg.ILLEGAL_CHAR_ERR, diff --git a/jaxp/src/com/sun/org/apache/xalan/internal/xsltc/compiler/XSLTC.java b/jaxp/src/com/sun/org/apache/xalan/internal/xsltc/compiler/XSLTC.java index e9cca2f743..89cc1460e4 100644 --- a/jaxp/src/com/sun/org/apache/xalan/internal/xsltc/compiler/XSLTC.java +++ b/jaxp/src/com/sun/org/apache/xalan/internal/xsltc/compiler/XSLTC.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -26,7 +26,6 @@ package com.sun.org.apache.xalan.internal.xsltc.compiler; import com.sun.org.apache.bcel.internal.classfile.JavaClass; import com.sun.org.apache.xalan.internal.XalanConstants; import com.sun.org.apache.xalan.internal.utils.SecuritySupport; -import com.sun.org.apache.xalan.internal.utils.XMLSecurityManager; import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg; import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util; import com.sun.org.apache.xml.internal.dtm.DTM; @@ -49,6 +48,7 @@ import java.util.jar.JarOutputStream; import java.util.jar.Manifest; import javax.xml.XMLConstants; import jdk.xml.internal.JdkXmlFeatures; +import jdk.xml.internal.XMLSecurityManager; import org.xml.sax.InputSource; import org.xml.sax.XMLReader; @@ -483,7 +483,10 @@ public final class XSLTC { } } catch (Exception e) { - /*if (_debug)*/ e.printStackTrace(); + if (_debug) e.printStackTrace(); + if (ErrorMsg.XPATH_LIMIT.equals(e.getMessage())) { + return !_parser.errorsFound(); + } _parser.reportError(Constants.FATAL, new ErrorMsg(ErrorMsg.JAXP_COMPILE_ERR, e)); } catch (Error e) { diff --git a/jaxp/src/com/sun/org/apache/xalan/internal/xsltc/compiler/sym.java b/jaxp/src/com/sun/org/apache/xalan/internal/xsltc/compiler/sym.java index d64dc3fd04..88244a31ab 100644 --- a/jaxp/src/com/sun/org/apache/xalan/internal/xsltc/compiler/sym.java +++ b/jaxp/src/com/sun/org/apache/xalan/internal/xsltc/compiler/sym.java @@ -6,6 +6,8 @@ package com.sun.org.apache.xalan.internal.xsltc.compiler; +import java.util.Arrays; + /** CUP generated class containing symbol constants. */ public class sym { /* terminals */ @@ -63,4 +65,12 @@ public class sym { public static final int ATTRIBUTE = 41; public static final int GT = 19; public static final int NODE = 31; + /* + AXES: count once at DCOLON, + these axes names are therefore not counted: + NAMESPACE, FOLLOWINGSIBLING, CHILD, DESCENDANTORSELF, DESCENDANT + , PRECEDINGSIBLING, SELF, ANCESTORORSELF, PRECEDING, ANCESTOROR, PARENT, FOLLOWING, ATTRIBUTE + */ + public static final int[] OPERATORS = {GE, SLASH, ATSIGN, LPAREN, DCOLON, + MINUS, STAR, LT, OR, DIV, PLUS, LE, VBAR, MOD, EQ, LBRACK, DOLLAR, NE, GT}; } diff --git a/jaxp/src/com/sun/org/apache/xalan/internal/xsltc/compiler/util/ErrorMessages.java b/jaxp/src/com/sun/org/apache/xalan/internal/xsltc/compiler/util/ErrorMessages.java index cf83580147..bb1a6e8f56 100644 --- a/jaxp/src/com/sun/org/apache/xalan/internal/xsltc/compiler/util/ErrorMessages.java +++ b/jaxp/src/com/sun/org/apache/xalan/internal/xsltc/compiler/util/ErrorMessages.java @@ -27,6 +27,7 @@ import java.util.ListResourceBundle; /** * @author Morten Jorgensen + * @LastModified: Jan 2022 */ public class ErrorMessages extends ListResourceBundle { @@ -1014,12 +1015,22 @@ public class ErrorMessages extends ListResourceBundle { "smaller templates." }, - {ErrorMsg.DESERIALIZE_TRANSLET_ERR, "When Java security is enabled, " + - "support for deserializing TemplatesImpl is disabled." + - "This can be overridden by setting the jdk.xml.enableTemplatesImplDeserialization" + - " system property to true."} + {ErrorMsg.DESERIALIZE_TRANSLET_ERR, "When Java security is enabled, " + + "support for deserializing TemplatesImpl is disabled. This can be " + + "overridden by setting the jdk.xml.enableTemplatesImplDeserialization" + + " system property to true."}, - }; + {ErrorMsg.XPATH_GROUP_LIMIT, + "JAXP0801001: the compiler encountered an XPath expression containing " + + "''{0}'' groups that exceeds the ''{1}'' limit set by ''{2}''."}, + + {ErrorMsg.XPATH_OPERATOR_LIMIT, + "JAXP0801002: the compiler encountered an XPath expression containing " + + "''{0}'' operators that exceeds the ''{1}'' limit set by ''{2}''."}, + {ErrorMsg.XPATH_TOTAL_OPERATOR_LIMIT, + "JAXP0801003: the compiler encountered XPath expressions with an accumulated " + + "''{0}'' operators that exceeds the ''{1}'' limit set by ''{2}''."}, + }; } } diff --git a/jaxp/src/com/sun/org/apache/xalan/internal/xsltc/compiler/util/ErrorMsg.java b/jaxp/src/com/sun/org/apache/xalan/internal/xsltc/compiler/util/ErrorMsg.java index 4192cf2d7e..365f6c747e 100644 --- a/jaxp/src/com/sun/org/apache/xalan/internal/xsltc/compiler/util/ErrorMsg.java +++ b/jaxp/src/com/sun/org/apache/xalan/internal/xsltc/compiler/util/ErrorMsg.java @@ -172,6 +172,11 @@ public final class ErrorMsg { public static final String DESERIALIZE_TRANSLET_ERR = "DESERIALIZE_TEMPLATES_ERR"; + public static final String XPATH_LIMIT = "XPATH_LIMIT"; + public static final String XPATH_GROUP_LIMIT = "XPATH_GROUP_LIMIT"; + public static final String XPATH_OPERATOR_LIMIT = "XPATH_OPERATOR_LIMIT"; + public static final String XPATH_TOTAL_OPERATOR_LIMIT = "XPATH_TOTAL_OPERATOR_LIMIT"; + // All error messages are localized and are stored in resource bundles. // This array and the following 4 strings are read from that bundle. private static ResourceBundle _bundle; @@ -208,7 +213,11 @@ public final class ErrorMsg { public ErrorMsg(String code, int line, Object param) { _code = code; _line = line; - _params = new Object[] { param }; + if (param instanceof Object[]) { + _params = (Object[])param; + } else { + _params = new Object[] { param }; + } } public ErrorMsg(String code, Object param) { diff --git a/jaxp/src/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerFactoryImpl.java b/jaxp/src/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerFactoryImpl.java index af487f04e5..7a4350d544 100644 --- a/jaxp/src/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerFactoryImpl.java +++ b/jaxp/src/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerFactoryImpl.java @@ -27,7 +27,7 @@ import com.sun.org.apache.xalan.internal.XalanConstants; import com.sun.org.apache.xalan.internal.utils.FeaturePropertyBase.State; import com.sun.org.apache.xalan.internal.utils.ObjectFactory; import com.sun.org.apache.xalan.internal.utils.SecuritySupport; -import com.sun.org.apache.xalan.internal.utils.XMLSecurityManager; +import jdk.xml.internal.XMLSecurityManager; import com.sun.org.apache.xalan.internal.utils.XMLSecurityPropertyManager; import com.sun.org.apache.xalan.internal.utils.XMLSecurityPropertyManager.Property; import com.sun.org.apache.xalan.internal.xsltc.compiler.Constants; diff --git a/jaxp/src/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerImpl.java b/jaxp/src/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerImpl.java index 019fcbbfc7..0e2b7424ca 100644 --- a/jaxp/src/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerImpl.java +++ b/jaxp/src/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -24,7 +24,6 @@ package com.sun.org.apache.xalan.internal.xsltc.trax; import com.sun.org.apache.xalan.internal.XalanConstants; -import com.sun.org.apache.xalan.internal.utils.XMLSecurityManager; import com.sun.org.apache.xalan.internal.utils.SecuritySupport; import com.sun.org.apache.xalan.internal.xsltc.DOM; import com.sun.org.apache.xalan.internal.xsltc.DOMCache; @@ -80,6 +79,7 @@ import javax.xml.transform.stax.StAXResult; import javax.xml.transform.stax.StAXSource; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; +import jdk.xml.internal.XMLSecurityManager; import jdk.xml.internal.JdkXmlUtils; import org.xml.sax.ContentHandler; import org.xml.sax.InputSource; diff --git a/jaxp/src/com/sun/org/apache/xalan/internal/xsltc/trax/Util.java b/jaxp/src/com/sun/org/apache/xalan/internal/xsltc/trax/Util.java index 91d8491798..a54208573f 100644 --- a/jaxp/src/com/sun/org/apache/xalan/internal/xsltc/trax/Util.java +++ b/jaxp/src/com/sun/org/apache/xalan/internal/xsltc/trax/Util.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. */ /* * Copyright 2001-2004 The Apache Software Foundation. @@ -39,7 +39,7 @@ import javax.xml.transform.stax.StAXSource; import javax.xml.transform.stream.StreamSource; import jdk.xml.internal.JdkXmlFeatures; import jdk.xml.internal.JdkXmlUtils; -import com.sun.org.apache.xalan.internal.utils.XMLSecurityManager; +import jdk.xml.internal.XMLSecurityManager; import com.sun.org.apache.xalan.internal.xsltc.compiler.XSLTC; import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg; @@ -118,9 +118,11 @@ public final class Util { (XMLSecurityManager)xsltc.getProperty(XalanConstants.SECURITY_MANAGER); if (securityManager != null) { for (XMLSecurityManager.Limit limit : XMLSecurityManager.Limit.values()) { - lastProperty = limit.apiProperty(); - reader.setProperty(lastProperty, - securityManager.getLimitValueAsString(limit)); + if (limit.isSupported(XMLSecurityManager.Processor.PARSER)) { + lastProperty = limit.apiProperty(); + reader.setProperty(lastProperty, + securityManager.getLimitValueAsString(limit)); + } } if (securityManager.printEntityCountInfo()) { lastProperty = XalanConstants.JDK_ENTITY_COUNT_INFO; diff --git a/jaxp/src/com/sun/org/apache/xml/internal/utils/XMLReaderManager.java b/jaxp/src/com/sun/org/apache/xml/internal/utils/XMLReaderManager.java index 39a5e88981..71a9cf14d6 100644 --- a/jaxp/src/com/sun/org/apache/xml/internal/utils/XMLReaderManager.java +++ b/jaxp/src/com/sun/org/apache/xml/internal/utils/XMLReaderManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved. */ /* * Copyright 1999-2004 The Apache Software Foundation. @@ -23,11 +23,11 @@ package com.sun.org.apache.xml.internal.utils; import com.sun.org.apache.xalan.internal.XalanConstants; import com.sun.org.apache.xalan.internal.utils.SecuritySupport; -import com.sun.org.apache.xalan.internal.utils.XMLSecurityManager; import java.util.HashMap; import javax.xml.XMLConstants; import jdk.xml.internal.JdkXmlUtils; +import jdk.xml.internal.XMLSecurityManager; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; @@ -133,9 +133,11 @@ public class XMLReaderManager { try { if (_xmlSecurityManager != null) { for (XMLSecurityManager.Limit limit : XMLSecurityManager.Limit.values()) { - lastProperty = limit.apiProperty(); - reader.setProperty(lastProperty, - _xmlSecurityManager.getLimitValueAsString(limit)); + if (limit.isSupported(XMLSecurityManager.Processor.PARSER)) { + lastProperty = limit.apiProperty(); + reader.setProperty(lastProperty, + _xmlSecurityManager.getLimitValueAsString(limit)); + } } if (_xmlSecurityManager.printEntityCountInfo()) { lastProperty = XalanConstants.JDK_ENTITY_COUNT_INFO; diff --git a/jaxp/src/com/sun/org/apache/xpath/internal/XPath.java b/jaxp/src/com/sun/org/apache/xpath/internal/XPath.java index 2734cc46ec..628ac7c91e 100644 --- a/jaxp/src/com/sun/org/apache/xpath/internal/XPath.java +++ b/jaxp/src/com/sun/org/apache/xpath/internal/XPath.java @@ -30,6 +30,7 @@ import javax.xml.transform.TransformerException; import com.sun.org.apache.xalan.internal.res.XSLMessages; import com.sun.org.apache.xml.internal.dtm.DTM; +import com.sun.org.apache.xml.internal.utils.DefaultErrorHandler; import com.sun.org.apache.xml.internal.utils.PrefixResolver; import com.sun.org.apache.xml.internal.utils.SAXSourceLocator; import com.sun.org.apache.xpath.internal.compiler.Compiler; @@ -38,6 +39,7 @@ import com.sun.org.apache.xpath.internal.compiler.XPathParser; import com.sun.org.apache.xpath.internal.functions.Function; import com.sun.org.apache.xpath.internal.objects.XObject; import com.sun.org.apache.xpath.internal.res.XPATHErrorResources; +import jdk.xml.internal.XMLSecurityManager; /** * The XPath class wraps an expression object and provides general services @@ -162,40 +164,11 @@ public class XPath implements Serializable, ExpressionOwner * * @throws javax.xml.transform.TransformerException if syntax or other error. */ - public XPath( - String exprString, SourceLocator locator, PrefixResolver prefixResolver, int type, - ErrorListener errorListener) - throws javax.xml.transform.TransformerException + public XPath(String exprString, SourceLocator locator, PrefixResolver prefixResolver, + int type, ErrorListener errorListener) + throws TransformerException { - initFunctionTable(); - if(null == errorListener) - errorListener = new com.sun.org.apache.xml.internal.utils.DefaultErrorHandler(); - - m_patternString = exprString; - - XPathParser parser = new XPathParser(errorListener, locator); - Compiler compiler = new Compiler(errorListener, locator, m_funcTable); - - if (SELECT == type) - parser.initXPath(compiler, exprString, prefixResolver); - else if (MATCH == type) - parser.initMatchPattern(compiler, exprString, prefixResolver); - else - throw new RuntimeException(XSLMessages.createXPATHMessage( - XPATHErrorResources.ER_CANNOT_DEAL_XPATH_TYPE, - new Object[]{Integer.toString(type)})); - - // System.out.println("----------------"); - Expression expr = compiler.compileExpression(0); - - // System.out.println("expr: "+expr); - this.setExpression(expr); - - if((null != locator) && locator instanceof ExpressionNode) - { - expr.exprSetParent((ExpressionNode)locator); - } - + this(exprString, locator, prefixResolver, type, errorListener, null); } /** @@ -209,22 +182,27 @@ public class XPath implements Serializable, ExpressionOwner * namespace URIs. * @param type one of {@link #SELECT} or {@link #MATCH}. * @param errorListener The error listener, or null if default should be used. + * @param funcTable the function table + * @param xmlSecMgr the XML security manager * * @throws javax.xml.transform.TransformerException if syntax or other error. */ - public XPath( - String exprString, SourceLocator locator, - PrefixResolver prefixResolver, int type, - ErrorListener errorListener, FunctionTable aTable) - throws javax.xml.transform.TransformerException + public XPath(String exprString, SourceLocator locator, PrefixResolver prefixResolver, + int type, ErrorListener errorListener, FunctionTable funcTable, + XMLSecurityManager xmlSecMgr) + throws TransformerException { - m_funcTable = aTable; + if (funcTable == null) { + initFunctionTable(); + } else { + m_funcTable = funcTable; + } if(null == errorListener) - errorListener = new com.sun.org.apache.xml.internal.utils.DefaultErrorHandler(); + errorListener = new DefaultErrorHandler(); m_patternString = exprString; - XPathParser parser = new XPathParser(errorListener, locator); + XPathParser parser = new XPathParser(errorListener, locator, xmlSecMgr); Compiler compiler = new Compiler(errorListener, locator, m_funcTable); if (SELECT == type) @@ -263,13 +241,32 @@ public class XPath implements Serializable, ExpressionOwner * * @throws javax.xml.transform.TransformerException if syntax or other error. */ - public XPath( - String exprString, SourceLocator locator, PrefixResolver prefixResolver, int type) - throws javax.xml.transform.TransformerException + public XPath(String exprString, SourceLocator locator, PrefixResolver prefixResolver, + int type) + throws TransformerException { this(exprString, locator, prefixResolver, type, null); } + /** + * Constructs an XPath object. + * + * @param exprString The XPath expression. + * @param locator The location of the expression, may be null. + * @param prefixResolver A prefix resolver to use to resolve prefixes to + * namespace URIs. + * @param type one of {@link #SELECT} or {@link #MATCH}. + * @param errorListener The error listener, or null if default should be used. + * @param funcTable the function table + * @throws TransformerException + */ + public XPath(String exprString, SourceLocator locator, PrefixResolver prefixResolver, + int type, ErrorListener errorListener, FunctionTable funcTable) + throws TransformerException + { + this(exprString, locator, prefixResolver, type, errorListener, funcTable, null); + } + /** * Construct an XPath object. * diff --git a/jaxp/src/com/sun/org/apache/xpath/internal/compiler/Lexer.java b/jaxp/src/com/sun/org/apache/xpath/internal/compiler/Lexer.java index 5af6f188f6..fa42d1a4a6 100644 --- a/jaxp/src/com/sun/org/apache/xpath/internal/compiler/Lexer.java +++ b/jaxp/src/com/sun/org/apache/xpath/internal/compiler/Lexer.java @@ -24,8 +24,13 @@ package com.sun.org.apache.xpath.internal.compiler; import java.util.Vector; +import com.sun.org.apache.xalan.internal.res.XSLMessages; import com.sun.org.apache.xml.internal.utils.PrefixResolver; import com.sun.org.apache.xpath.internal.res.XPATHErrorResources; +import java.util.Objects; +import javax.xml.transform.TransformerException; +import jdk.xml.internal.XMLSecurityManager; +import jdk.xml.internal.XMLSecurityManager.Limit; /** * This class is in charge of lexical processing of the XPath @@ -71,6 +76,24 @@ class Lexer */ private int m_patternMapSize; + // XML security manager + XMLSecurityManager m_xmlSecMgr; + + // operator limit + private int m_opCountLimit; + + // group limit + private int m_grpCountLimit; + + // count of operators + private int m_opCount; + + // count of groups + private int m_grpCount; + + // indicate whether the current token is a literal + private boolean isLiteral = false; + /** * Create a Lexer object. * @@ -78,14 +101,22 @@ class Lexer * @param resolver The prefix resolver for mapping qualified name prefixes * to namespace URIs. * @param xpathProcessor The parser that is processing strings to opcodes. + * @param xmlSecMgr the XML security manager */ Lexer(Compiler compiler, PrefixResolver resolver, - XPathParser xpathProcessor) + XPathParser xpathProcessor, XMLSecurityManager xmlSecMgr) { - m_compiler = compiler; m_namespaceContext = resolver; m_processor = xpathProcessor; + m_xmlSecMgr = xmlSecMgr; + /** + * No limits if XML Security Manager is null. Applications using XPath through + * the public API always have a XMLSecurityManager. Applications invoking + * the internal XPath API shall consider using the public API instead. + */ + m_opCountLimit = (xmlSecMgr != null) ? xmlSecMgr.getLimit(Limit.XPATH_OP_LIMIT) : 0; + m_grpCountLimit = (xmlSecMgr != null) ? xmlSecMgr.getLimit(Limit.XPATH_GROUP_LIMIT) : 0; } /** @@ -136,7 +167,7 @@ class Lexer switch (c) { - case '\"' : + case Token.DQ : { if (startSubstring != -1) { @@ -171,7 +202,7 @@ class Lexer } } break; - case '\'' : + case Token.SQ : if (startSubstring != -1) { isNum = false; @@ -190,9 +221,9 @@ class Lexer startSubstring = i; - for (i++; (i < nChars) && ((c = pat.charAt(i)) != '\''); i++); + for (i++; (i < nChars) && ((c = pat.charAt(i)) != Token.SQ); i++); - if (c == '\'' && i < nChars) + if (c == Token.SQ && i < nChars) { addToTokenQueue(pat.substring(startSubstring, i + 1)); @@ -220,18 +251,24 @@ class Lexer } else { - addToTokenQueue(pat.substring(startSubstring, i)); + // check operator symbol + String s = pat.substring(startSubstring, i); + if (Token.contains(s)) { + m_opCount++; + isLiteral = false; + } + addToTokenQueue(s); } startSubstring = -1; } break; - case '@' : + case Token.AT : isAttrName = true; // fall-through on purpose - case '-' : - if ('-' == c) + case Token.MINUS : + if (Token.MINUS == c) { if (!(isNum || (startSubstring == -1))) { @@ -242,22 +279,22 @@ class Lexer } // fall-through on purpose - case '(' : - case '[' : - case ')' : - case ']' : - case '|' : - case '/' : - case '*' : - case '+' : - case '=' : - case ',' : + case Token.LPAREN : + case Token.LBRACK : + case Token.RPAREN : + case Token.RBRACK : + case Token.VBAR : + case Token.SLASH : + case Token.STAR : + case Token.PLUS : + case Token.EQ : + case Token.COMMA : case '\\' : // Unused at the moment case '^' : // Unused at the moment - case '!' : // Unused at the moment - case '$' : - case '<' : - case '>' : + case Token.EM : // Unused at the moment + case Token.DOLLAR : + case Token.LT : + case Token.GT : if (startSubstring != -1) { isNum = false; @@ -275,11 +312,11 @@ class Lexer startSubstring = -1; } - else if (('/' == c) && isStartOfPat) + else if ((Token.SLASH == c) && isStartOfPat) { isStartOfPat = mapPatternElemPos(nesting, isStartOfPat, isAttrName); } - else if ('*' == c) + else if (Token.STAR == c) { isStartOfPat = mapPatternElemPos(nesting, isStartOfPat, isAttrName); isAttrName = false; @@ -287,7 +324,7 @@ class Lexer if (0 == nesting) { - if ('|' == c) + if (Token.VBAR == c) { if (null != targetStrings) { @@ -298,18 +335,32 @@ class Lexer } } - if ((')' == c) || (']' == c)) + if ((Token.RPAREN == c) || (Token.RBRACK == c)) { nesting--; } - else if (('(' == c) || ('[' == c)) + else if ((Token.LPAREN == c) || (Token.LBRACK == c)) { nesting++; + if (!isLiteral && (Token.LPAREN == c)) { + m_grpCount++; + m_opCount++; + isLiteral = false; + } + } + + if ((Token.GT == c || Token.LT == c || Token.EQ == c) && Token.EQ != peekNext(pat, i)) { + m_opCount++; + isLiteral = false; + } + else if ((Token.LPAREN != c) && (Token.RPAREN != c) && (Token.RBRACK != c)) { + m_opCount++; + isLiteral = false; } addToTokenQueue(pat.substring(i, i + 1)); break; - case ':' : + case Token.COLON : if (i>0) { if (posOfNSSep == (i - 1)) @@ -324,7 +375,7 @@ class Lexer isAttrName = false; startSubstring = -1; posOfNSSep = -1; - + m_opCount++; addToTokenQueue(pat.substring(i - 1, i + 1)); break; @@ -337,6 +388,7 @@ class Lexer // fall through on purpose default : + isLiteral = true; if (-1 == startSubstring) { startSubstring = i; @@ -347,6 +399,20 @@ class Lexer isNum = Character.isDigit(c); } } + if (m_grpCountLimit > 0 && m_grpCount > m_grpCountLimit) { + throw new TransformerException(XSLMessages.createXPATHMessage( + XPATHErrorResources.ER_XPATH_GROUP_LIMIT, + new Object[]{Integer.toString(m_grpCount), + Integer.toString(m_grpCountLimit), + m_xmlSecMgr.getStateLiteral(Limit.XPATH_GROUP_LIMIT)})); + } + if (m_opCountLimit > 0 && m_opCount > m_opCountLimit) { + throw new TransformerException(XSLMessages.createXPATHMessage( + XPATHErrorResources.ER_XPATH_OPERATOR_LIMIT, + new Object[]{Integer.toString(m_opCount), + Integer.toString(m_opCountLimit), + m_xmlSecMgr.getStateLiteral(Limit.XPATH_OP_LIMIT)})); + } } if (startSubstring != -1) @@ -377,6 +443,19 @@ class Lexer m_processor.m_queueMark = 0; } + /** + * Peeks at the next character without advancing the index. + * @param s the input string + * @param index the current index + * @return the next char + */ + private char peekNext(String s, int index) { + if (index >= 0 && s.length() > index) { + return s.charAt(index + 1); + } + return 0; + } + /** * Record the current position on the token queue as long as * this is a top-level element. Must be called before the @@ -499,7 +578,7 @@ class Lexer resetTokenMark(tokPos + 1); - if (m_processor.lookahead('(', 1)) + if (m_processor.lookahead(Token.LPAREN, 1)) { int tok = getKeywordToken(m_processor.m_token); @@ -529,14 +608,14 @@ class Lexer } else { - if (m_processor.tokenIs('@')) + if (m_processor.tokenIs(Token.AT)) { tokPos++; resetTokenMark(tokPos + 1); } - if (m_processor.lookahead(':', 1)) + if (m_processor.lookahead(Token.COLON, 1)) { tokPos += 2; } @@ -565,13 +644,13 @@ class Lexer * @param posOfNSSep The position of the namespace seperator (':'). * @param posOfScan The end of the name index. * - * @throws javax.xml.transform.TransformerException + * @throws TransformerException * * @return -1 always. */ private int mapNSTokens(String pat, int startSubstring, int posOfNSSep, int posOfScan) - throws javax.xml.transform.TransformerException + throws TransformerException { String prefix = ""; diff --git a/jaxp/src/com/sun/org/apache/xpath/internal/compiler/Token.java b/jaxp/src/com/sun/org/apache/xpath/internal/compiler/Token.java new file mode 100644 index 0000000000..40d84035f7 --- /dev/null +++ b/jaxp/src/com/sun/org/apache/xpath/internal/compiler/Token.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.org.apache.xpath.internal.compiler; + +import java.util.Arrays; + +/** + * XPath tokens + */ +public final class Token { + static final char EM = '!'; + static final char EQ = '='; + static final char LT = '<'; + static final char GT = '>'; + static final char PLUS = '+'; + static final char MINUS = '-'; + static final char STAR = '*'; + static final char VBAR = '|'; + static final char SLASH = '/'; + static final char LBRACK = '['; + static final char RBRACK = ']'; + static final char LPAREN = '('; + static final char RPAREN = ')'; + static final char COMMA = ','; + static final char DOT = '.'; + static final char AT = '@'; + static final char US = '_'; + static final char COLON = ':'; + static final char SQ = '\''; + static final char DQ = '"'; + static final char DOLLAR = '$'; + + static final String OR = "or"; + static final String AND = "and"; + static final String DIV = "div"; + static final String MOD = "mod"; + static final String QUO = "quo"; + static final String DDOT = ".."; + static final String DCOLON = "::"; + static final String ATTR = "attribute"; + static final String CHILD = "child"; + + static final String[] OPERATORS = {OR, AND, DIV, MOD, QUO, + DDOT, DCOLON, ATTR, CHILD}; + + public static boolean contains(String str) { + for(String op: OPERATORS) { + if (str.equals(op)) { + return true; + } + } + return false; + } + + private Token() { + //to prevent instantiation + } +} diff --git a/jaxp/src/com/sun/org/apache/xpath/internal/compiler/XPathParser.java b/jaxp/src/com/sun/org/apache/xpath/internal/compiler/XPathParser.java index bd19dffdd7..91404306a7 100644 --- a/jaxp/src/com/sun/org/apache/xpath/internal/compiler/XPathParser.java +++ b/jaxp/src/com/sun/org/apache/xpath/internal/compiler/XPathParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. */ /* * Copyright 1999-2004 The Apache Software Foundation. @@ -21,9 +21,6 @@ */ package com.sun.org.apache.xpath.internal.compiler; -import javax.xml.transform.ErrorListener; -import javax.xml.transform.TransformerException; - import com.sun.org.apache.xalan.internal.res.XSLMessages; import com.sun.org.apache.xml.internal.utils.PrefixResolver; import com.sun.org.apache.xpath.internal.XPathProcessorException; @@ -31,12 +28,17 @@ import com.sun.org.apache.xpath.internal.domapi.XPathStylesheetDOM3Exception; import com.sun.org.apache.xpath.internal.objects.XNumber; import com.sun.org.apache.xpath.internal.objects.XString; import com.sun.org.apache.xpath.internal.res.XPATHErrorResources; +import javax.xml.transform.ErrorListener; +import javax.xml.transform.SourceLocator; +import javax.xml.transform.TransformerException; +import jdk.xml.internal.XMLSecurityManager; +import jdk.xml.internal.XMLSecurityManager.Limit; /** * Tokenizes and parses XPath expressions. This should really be named * XPathParserImpl, and may be renamed in the future. * @xsl.usage general - * @LastModified: May 2019 + * @LastModified: Jan 2022 */ public class XPathParser { @@ -77,13 +79,18 @@ public class XPathParser // counts open predicates private int countPredicate; + // XML security manager + XMLSecurityManager m_xmlSecMgr; + /** * The parser constructor. */ - public XPathParser(ErrorListener errorListener, javax.xml.transform.SourceLocator sourceLocator) + public XPathParser(ErrorListener errorListener, SourceLocator sourceLocator, + XMLSecurityManager xmlSecMgr) { m_errorListener = errorListener; m_sourceLocator = sourceLocator; + m_xmlSecMgr = xmlSecMgr; } /** @@ -101,18 +108,18 @@ public class XPathParser * @param namespaceContext An object that is able to resolve prefixes in * the XPath to namespaces. * - * @throws javax.xml.transform.TransformerException + * @throws TransformerException */ public void initXPath( Compiler compiler, String expression, PrefixResolver namespaceContext) - throws javax.xml.transform.TransformerException + throws TransformerException { m_ops = compiler; m_namespaceContext = namespaceContext; m_functionTable = compiler.getFunctionTable(); - Lexer lexer = new Lexer(compiler, namespaceContext, this); + Lexer lexer = new Lexer(compiler, namespaceContext, this, m_xmlSecMgr); lexer.tokenize(expression); @@ -180,18 +187,18 @@ public class XPathParser * @param namespaceContext An object that is able to resolve prefixes in * the XPath to namespaces. * - * @throws javax.xml.transform.TransformerException + * @throws TransformerException */ public void initMatchPattern( Compiler compiler, String expression, PrefixResolver namespaceContext) - throws javax.xml.transform.TransformerException + throws TransformerException { m_ops = compiler; m_namespaceContext = namespaceContext; m_functionTable = compiler.getFunctionTable(); - Lexer lexer = new Lexer(compiler, namespaceContext, this); + Lexer lexer = new Lexer(compiler, namespaceContext, this, m_xmlSecMgr); lexer.tokenize(expression); @@ -384,9 +391,9 @@ public class XPathParser if ((m_queueMark - n) > 0) { String lookbehind = (String) m_ops.m_tokenQueue.elementAt(m_queueMark - (n - 1)); - char c0 = (lookbehind == null) ? '|' : lookbehind.charAt(0); + char c0 = (lookbehind == null) ? Token.VBAR : lookbehind.charAt(0); - hasToken = (c0 == '|') ? false : true; + hasToken = (c0 == Token.VBAR) ? false : true; } else { @@ -498,10 +505,10 @@ public class XPathParser * * @param expected The string to be expected. * - * @throws javax.xml.transform.TransformerException + * @throws TransformerException */ private final void consumeExpected(String expected) - throws javax.xml.transform.TransformerException + throws TransformerException { if (tokenIs(expected)) @@ -526,10 +533,10 @@ public class XPathParser * * @param expected the character to be expected. * - * @throws javax.xml.transform.TransformerException + * @throws TransformerException */ private final void consumeExpected(char expected) - throws javax.xml.transform.TransformerException + throws TransformerException { if (tokenIs(expected)) @@ -796,9 +803,9 @@ public class XPathParser * Expr ::= OrExpr * * - * @throws javax.xml.transform.TransformerException + * @throws TransformerException */ - protected void Expr() throws javax.xml.transform.TransformerException + protected void Expr() throws TransformerException { OrExpr(); } @@ -810,16 +817,16 @@ public class XPathParser * | OrExpr 'or' AndExpr * * - * @throws javax.xml.transform.TransformerException + * @throws TransformerException */ - protected void OrExpr() throws javax.xml.transform.TransformerException + protected void OrExpr() throws TransformerException { int opPos = m_ops.getOp(OpMap.MAPINDEX_LENGTH); AndExpr(); - if ((null != m_token) && tokenIs("or")) + if ((null != m_token) && tokenIs(Token.OR)) { nextToken(); insertOp(opPos, 2, OpCodes.OP_OR); @@ -837,16 +844,16 @@ public class XPathParser * | AndExpr 'and' EqualityExpr * * - * @throws javax.xml.transform.TransformerException + * @throws TransformerException */ - protected void AndExpr() throws javax.xml.transform.TransformerException + protected void AndExpr() throws TransformerException { int opPos = m_ops.getOp(OpMap.MAPINDEX_LENGTH); EqualityExpr(-1); - if ((null != m_token) && tokenIs("and")) + if ((null != m_token) && tokenIs(Token.AND)) { nextToken(); insertOp(opPos, 2, OpCodes.OP_AND); @@ -870,9 +877,9 @@ public class XPathParser * * @return the position at the end of the equality expression. * - * @throws javax.xml.transform.TransformerException + * @throws TransformerException */ - protected int EqualityExpr(int addPos) throws javax.xml.transform.TransformerException + protected int EqualityExpr(int addPos) throws TransformerException { int opPos = m_ops.getOp(OpMap.MAPINDEX_LENGTH); @@ -884,7 +891,7 @@ public class XPathParser if (null != m_token) { - if (tokenIs('!') && lookahead('=', 1)) + if (tokenIs(Token.EM) && lookahead(Token.EQ, 1)) { nextToken(); nextToken(); @@ -897,7 +904,7 @@ public class XPathParser m_ops.getOp(addPos + opPlusLeftHandLen + 1) + opPlusLeftHandLen); addPos += 2; } - else if (tokenIs('=')) + else if (tokenIs(Token.EQ)) { nextToken(); insertOp(addPos, 2, OpCodes.OP_EQUALS); @@ -930,9 +937,9 @@ public class XPathParser * * @return the position at the end of the relational expression. * - * @throws javax.xml.transform.TransformerException + * @throws TransformerException */ - protected int RelationalExpr(int addPos) throws javax.xml.transform.TransformerException + protected int RelationalExpr(int addPos) throws TransformerException { int opPos = m_ops.getOp(OpMap.MAPINDEX_LENGTH); @@ -944,11 +951,11 @@ public class XPathParser if (null != m_token) { - if (tokenIs('<')) + if (tokenIs(Token.LT)) { nextToken(); - if (tokenIs('=')) + if (tokenIs(Token.EQ)) { nextToken(); insertOp(addPos, 2, OpCodes.OP_LTE); @@ -965,11 +972,11 @@ public class XPathParser m_ops.getOp(addPos + opPlusLeftHandLen + 1) + opPlusLeftHandLen); addPos += 2; } - else if (tokenIs('>')) + else if (tokenIs(Token.GT)) { nextToken(); - if (tokenIs('=')) + if (tokenIs(Token.EQ)) { nextToken(); insertOp(addPos, 2, OpCodes.OP_GTE); @@ -1005,9 +1012,9 @@ public class XPathParser * * @return the position at the end of the equality expression. * - * @throws javax.xml.transform.TransformerException + * @throws TransformerException */ - protected int AdditiveExpr(int addPos) throws javax.xml.transform.TransformerException + protected int AdditiveExpr(int addPos) throws TransformerException { int opPos = m_ops.getOp(OpMap.MAPINDEX_LENGTH); @@ -1019,7 +1026,7 @@ public class XPathParser if (null != m_token) { - if (tokenIs('+')) + if (tokenIs(Token.PLUS)) { nextToken(); insertOp(addPos, 2, OpCodes.OP_PLUS); @@ -1031,7 +1038,7 @@ public class XPathParser m_ops.getOp(addPos + opPlusLeftHandLen + 1) + opPlusLeftHandLen); addPos += 2; } - else if (tokenIs('-')) + else if (tokenIs(Token.MINUS)) { nextToken(); insertOp(addPos, 2, OpCodes.OP_MINUS); @@ -1063,9 +1070,9 @@ public class XPathParser * * @return the position at the end of the equality expression. * - * @throws javax.xml.transform.TransformerException + * @throws TransformerException */ - protected int MultiplicativeExpr(int addPos) throws javax.xml.transform.TransformerException + protected int MultiplicativeExpr(int addPos) throws TransformerException { int opPos = m_ops.getOp(OpMap.MAPINDEX_LENGTH); @@ -1077,7 +1084,7 @@ public class XPathParser if (null != m_token) { - if (tokenIs('*')) + if (tokenIs(Token.STAR)) { nextToken(); insertOp(addPos, 2, OpCodes.OP_MULT); @@ -1089,7 +1096,7 @@ public class XPathParser m_ops.getOp(addPos + opPlusLeftHandLen + 1) + opPlusLeftHandLen); addPos += 2; } - else if (tokenIs("div")) + else if (tokenIs(Token.DIV)) { nextToken(); insertOp(addPos, 2, OpCodes.OP_DIV); @@ -1101,7 +1108,7 @@ public class XPathParser m_ops.getOp(addPos + opPlusLeftHandLen + 1) + opPlusLeftHandLen); addPos += 2; } - else if (tokenIs("mod")) + else if (tokenIs(Token.MOD)) { nextToken(); insertOp(addPos, 2, OpCodes.OP_MOD); @@ -1113,7 +1120,7 @@ public class XPathParser m_ops.getOp(addPos + opPlusLeftHandLen + 1) + opPlusLeftHandLen); addPos += 2; } - else if (tokenIs("quo")) + else if (tokenIs(Token.QUO)) { nextToken(); insertOp(addPos, 2, OpCodes.OP_QUO); @@ -1136,15 +1143,15 @@ public class XPathParser * | '-' UnaryExpr * * - * @throws javax.xml.transform.TransformerException + * @throws TransformerException */ - protected void UnaryExpr() throws javax.xml.transform.TransformerException + protected void UnaryExpr() throws TransformerException { int opPos = m_ops.getOp(OpMap.MAPINDEX_LENGTH); boolean isNeg = false; - if (m_tokenChar == '-') + if (m_tokenChar == Token.MINUS) { nextToken(); appendOp(2, OpCodes.OP_NEG); @@ -1164,9 +1171,9 @@ public class XPathParser * StringExpr ::= Expr * * - * @throws javax.xml.transform.TransformerException + * @throws TransformerException */ - protected void StringExpr() throws javax.xml.transform.TransformerException + protected void StringExpr() throws TransformerException { int opPos = m_ops.getOp(OpMap.MAPINDEX_LENGTH); @@ -1184,9 +1191,9 @@ public class XPathParser * StringExpr ::= Expr * * - * @throws javax.xml.transform.TransformerException + * @throws TransformerException */ - protected void BooleanExpr() throws javax.xml.transform.TransformerException + protected void BooleanExpr() throws TransformerException { int opPos = m_ops.getOp(OpMap.MAPINDEX_LENGTH); @@ -1210,9 +1217,9 @@ public class XPathParser * NumberExpr ::= Expr * * - * @throws javax.xml.transform.TransformerException + * @throws TransformerException */ - protected void NumberExpr() throws javax.xml.transform.TransformerException + protected void NumberExpr() throws TransformerException { int opPos = m_ops.getOp(OpMap.MAPINDEX_LENGTH); @@ -1235,9 +1242,9 @@ public class XPathParser * | UnionExpr '|' PathExpr * * - * @throws javax.xml.transform.TransformerException + * @throws TransformerException */ - protected void UnionExpr() throws javax.xml.transform.TransformerException + protected void UnionExpr() throws TransformerException { int opPos = m_ops.getOp(OpMap.MAPINDEX_LENGTH); @@ -1248,7 +1255,7 @@ public class XPathParser { PathExpr(); - if (tokenIs('|')) + if (tokenIs(Token.VBAR)) { if (false == foundUnion) { @@ -1281,9 +1288,9 @@ public class XPathParser * @throws XSLProcessorException thrown if the active ProblemListener and XPathContext decide * the error condition is severe enough to halt processing. * - * @throws javax.xml.transform.TransformerException + * @throws TransformerException */ - protected void PathExpr() throws javax.xml.transform.TransformerException + protected void PathExpr() throws TransformerException { int opPos = m_ops.getOp(OpMap.MAPINDEX_LENGTH); @@ -1296,7 +1303,7 @@ public class XPathParser // have been inserted. boolean locationPathStarted = (filterExprMatch==FILTER_MATCH_PREDICATES); - if (tokenIs('/')) + if (tokenIs(Token.SLASH)) { nextToken(); @@ -1346,9 +1353,9 @@ public class XPathParser * FilterExpr that was just a PrimaryExpr; or * FILTER_MATCH_FAILED, if this method did not match a FilterExpr * - * @throws javax.xml.transform.TransformerException + * @throws TransformerException */ - protected int FilterExpr() throws javax.xml.transform.TransformerException + protected int FilterExpr() throws TransformerException { int opPos = m_ops.getOp(OpMap.MAPINDEX_LENGTH); @@ -1357,13 +1364,13 @@ public class XPathParser if (PrimaryExpr()) { - if (tokenIs('[')) + if (tokenIs(Token.LBRACK)) { // int locationPathOpPos = opPos; insertOp(opPos, 2, OpCodes.OP_LOCATIONPATH); - while (tokenIs('[')) + while (tokenIs(Token.LBRACK)) { Predicate(); } @@ -1401,16 +1408,16 @@ public class XPathParser * * @return true if this method successfully matched a PrimaryExpr * - * @throws javax.xml.transform.TransformerException + * @throws TransformerException * */ - protected boolean PrimaryExpr() throws javax.xml.transform.TransformerException + protected boolean PrimaryExpr() throws TransformerException { boolean matchFound; int opPos = m_ops.getOp(OpMap.MAPINDEX_LENGTH); - if ((m_tokenChar == '\'') || (m_tokenChar == '"')) + if ((m_tokenChar == Token.SQ) || (m_tokenChar == Token.DQ)) { appendOp(2, OpCodes.OP_LITERAL); Literal(); @@ -1420,7 +1427,7 @@ public class XPathParser matchFound = true; } - else if (m_tokenChar == '$') + else if (m_tokenChar == Token.DOLLAR) { nextToken(); // consume '$' appendOp(2, OpCodes.OP_VARIABLE); @@ -1431,12 +1438,12 @@ public class XPathParser matchFound = true; } - else if (m_tokenChar == '(') + else if (m_tokenChar == Token.LPAREN) { nextToken(); appendOp(2, OpCodes.OP_GROUP); Expr(); - consumeExpected(')'); + consumeExpected(Token.RPAREN); m_ops.setOp(opPos + OpMap.MAPINDEX_LENGTH, m_ops.getOp(OpMap.MAPINDEX_LENGTH) - opPos); @@ -1454,7 +1461,7 @@ public class XPathParser matchFound = true; } - else if (lookahead('(', 1) || (lookahead(':', 1) && lookahead('(', 3))) + else if (lookahead(Token.LPAREN, 1) || (lookahead(Token.COLON, 1) && lookahead(Token.LPAREN, 3))) { matchFound = FunctionCall(); } @@ -1471,9 +1478,9 @@ public class XPathParser * Argument ::= Expr * * - * @throws javax.xml.transform.TransformerException + * @throws TransformerException */ - protected void Argument() throws javax.xml.transform.TransformerException + protected void Argument() throws TransformerException { int opPos = m_ops.getOp(OpMap.MAPINDEX_LENGTH); @@ -1491,14 +1498,14 @@ public class XPathParser * * @return true if, and only if, a FunctionCall was matched * - * @throws javax.xml.transform.TransformerException + * @throws TransformerException */ - protected boolean FunctionCall() throws javax.xml.transform.TransformerException + protected boolean FunctionCall() throws TransformerException { int opPos = m_ops.getOp(OpMap.MAPINDEX_LENGTH); - if (lookahead(':', 1)) + if (lookahead(Token.COLON, 1)) { appendOp(4, OpCodes.OP_EXTFUNCTION); @@ -1538,22 +1545,23 @@ public class XPathParser nextToken(); } - consumeExpected('('); + consumeExpected(Token.LPAREN); - while (!tokenIs(')') && m_token != null) + while (!tokenIs(Token.RPAREN) && m_token != null) { - if (tokenIs(',')) + if (tokenIs(Token.COMMA)) { - error(XPATHErrorResources.ER_FOUND_COMMA_BUT_NO_PRECEDING_ARG, null); //"Found ',' but no preceding argument!"); + //"Found ',' but no preceding argument!"); + error(XPATHErrorResources.ER_FOUND_COMMA_BUT_NO_PRECEDING_ARG, null); } Argument(); - if (!tokenIs(')')) + if (!tokenIs(Token.RPAREN)) { - consumeExpected(','); + consumeExpected(Token.COMMA); - if (tokenIs(')')) + if (tokenIs(Token.RPAREN)) { error(XPATHErrorResources.ER_FOUND_COMMA_BUT_NO_FOLLOWING_ARG, null); //"Found ',' but no following argument!"); @@ -1561,7 +1569,7 @@ public class XPathParser } } - consumeExpected(')'); + consumeExpected(Token.RPAREN); // Terminate for safety. m_ops.setOp(m_ops.getOp(OpMap.MAPINDEX_LENGTH), OpCodes.ENDOP); @@ -1580,9 +1588,9 @@ public class XPathParser * | AbsoluteLocationPath * * - * @throws javax.xml.transform.TransformerException + * @throws TransformerException */ - protected void LocationPath() throws javax.xml.transform.TransformerException + protected void LocationPath() throws TransformerException { int opPos = m_ops.getOp(OpMap.MAPINDEX_LENGTH); @@ -1590,7 +1598,7 @@ public class XPathParser // int locationPathOpPos = opPos; appendOp(2, OpCodes.OP_LOCATIONPATH); - boolean seenSlash = tokenIs('/'); + boolean seenSlash = tokenIs(Token.SLASH); if (seenSlash) { @@ -1631,17 +1639,17 @@ public class XPathParser * * @returns true if, and only if, a RelativeLocationPath was matched * - * @throws javax.xml.transform.TransformerException + * @throws TransformerException */ protected boolean RelativeLocationPath() - throws javax.xml.transform.TransformerException + throws TransformerException { if (!Step()) { return false; } - while (tokenIs('/')) + while (tokenIs(Token.SLASH)) { nextToken(); @@ -1663,13 +1671,13 @@ public class XPathParser * * @returns false if step was empty (or only a '/'); true, otherwise * - * @throws javax.xml.transform.TransformerException + * @throws TransformerException */ - protected boolean Step() throws javax.xml.transform.TransformerException + protected boolean Step() throws TransformerException { int opPos = m_ops.getOp(OpMap.MAPINDEX_LENGTH); - boolean doubleSlash = tokenIs('/'); + boolean doubleSlash = tokenIs(Token.SLASH); // At most a single '/' before each Step is consumed by caller; if the // first thing is a '/', that means we had '//' and the Step must not @@ -1701,11 +1709,11 @@ public class XPathParser opPos = m_ops.getOp(OpMap.MAPINDEX_LENGTH); } - if (tokenIs(".")) + if (tokenIs(Token.DOT)) { nextToken(); - if (tokenIs('[')) + if (tokenIs(Token.LBRACK)) { error(XPATHErrorResources.ER_PREDICATE_ILLEGAL_SYNTAX, null); //"'..[predicate]' or '.[predicate]' is illegal syntax. Use 'self::node()[predicate]' instead."); } @@ -1716,7 +1724,7 @@ public class XPathParser m_ops.setOp(m_ops.getOp(OpMap.MAPINDEX_LENGTH) - 2,4); m_ops.setOp(m_ops.getOp(OpMap.MAPINDEX_LENGTH) - 1, OpCodes.NODETYPE_NODE); } - else if (tokenIs("..")) + else if (tokenIs(Token.DDOT)) { nextToken(); appendOp(4, OpCodes.FROM_PARENT); @@ -1729,12 +1737,12 @@ public class XPathParser // There is probably a better way to test for this // transition... but it gets real hairy if you try // to do it in basis(). - else if (tokenIs('*') || tokenIs('@') || tokenIs('_') + else if (tokenIs(Token.STAR) || tokenIs(Token.AT) || tokenIs(Token.US) || (m_token!= null && Character.isLetter(m_token.charAt(0)))) { Basis(); - while (tokenIs('[')) + while (tokenIs(Token.LBRACK)) { Predicate(); } @@ -1763,23 +1771,23 @@ public class XPathParser * Basis ::= AxisName '::' NodeTest * | AbbreviatedBasis * - * @throws javax.xml.transform.TransformerException + * @throws TransformerException */ - protected void Basis() throws javax.xml.transform.TransformerException + protected void Basis() throws TransformerException { int opPos = m_ops.getOp(OpMap.MAPINDEX_LENGTH); int axesType; // The next blocks guarantee that a FROM_XXX will be added. - if (lookahead("::", 1)) + if (lookahead(Token.DCOLON, 1)) { axesType = AxisName(); nextToken(); nextToken(); } - else if (tokenIs('@')) + else if (tokenIs(Token.AT)) { axesType = OpCodes.FROM_ATTRIBUTES; @@ -1810,9 +1818,9 @@ public class XPathParser * * @return FROM_XXX axes type, found in {@link com.sun.org.apache.xpath.internal.compiler.Keywords}. * - * @throws javax.xml.transform.TransformerException + * @throws TransformerException */ - protected int AxisName() throws javax.xml.transform.TransformerException + protected int AxisName() throws TransformerException { Object val = Keywords.getAxisName(m_token); @@ -1838,12 +1846,12 @@ public class XPathParser * * @param axesType FROM_XXX axes type, found in {@link com.sun.org.apache.xpath.internal.compiler.Keywords}. * - * @throws javax.xml.transform.TransformerException + * @throws TransformerException */ - protected void NodeTest(int axesType) throws javax.xml.transform.TransformerException + protected void NodeTest(int axesType) throws TransformerException { - if (lookahead('(', 1)) + if (lookahead(Token.LPAREN, 1)) { Object nodeTestOp = Keywords.getNodeType(m_token); @@ -1861,17 +1869,17 @@ public class XPathParser m_ops.setOp(m_ops.getOp(OpMap.MAPINDEX_LENGTH), nt); m_ops.setOp(OpMap.MAPINDEX_LENGTH, m_ops.getOp(OpMap.MAPINDEX_LENGTH) + 1); - consumeExpected('('); + consumeExpected(Token.LPAREN); if (OpCodes.NODETYPE_PI == nt) { - if (!tokenIs(')')) + if (!tokenIs(Token.RPAREN)) { Literal(); } } - consumeExpected(')'); + consumeExpected(Token.RPAREN); } } else @@ -1881,9 +1889,9 @@ public class XPathParser m_ops.setOp(m_ops.getOp(OpMap.MAPINDEX_LENGTH), OpCodes.NODENAME); m_ops.setOp(OpMap.MAPINDEX_LENGTH, m_ops.getOp(OpMap.MAPINDEX_LENGTH) + 1); - if (lookahead(':', 1)) + if (lookahead(Token.COLON, 1)) { - if (tokenIs('*')) + if (tokenIs(Token.STAR)) { m_ops.setOp(m_ops.getOp(OpMap.MAPINDEX_LENGTH), OpCodes.ELEMWILDCARD); } @@ -1893,7 +1901,7 @@ public class XPathParser // Minimalist check for an NCName - just check first character // to distinguish from other possible tokens - if (!Character.isLetter(m_tokenChar) && !tokenIs('_')) + if (!Character.isLetter(m_tokenChar) && !tokenIs(Token.US)) { // "Node test that matches either NCName:* or QName was expected." error(XPATHErrorResources.ER_EXPECTED_NODE_TEST, null); @@ -1910,7 +1918,7 @@ public class XPathParser m_ops.setOp(OpMap.MAPINDEX_LENGTH, m_ops.getOp(OpMap.MAPINDEX_LENGTH) + 1); - if (tokenIs('*')) + if (tokenIs(Token.STAR)) { m_ops.setOp(m_ops.getOp(OpMap.MAPINDEX_LENGTH), OpCodes.ELEMWILDCARD); } @@ -1920,7 +1928,7 @@ public class XPathParser // Minimalist check for an NCName - just check first character // to distinguish from other possible tokens - if (!Character.isLetter(m_tokenChar) && !tokenIs('_')) + if (!Character.isLetter(m_tokenChar) && !tokenIs(Token.US)) { // "Node test that matches either NCName:* or QName was expected." error(XPATHErrorResources.ER_EXPECTED_NODE_TEST, null); @@ -1938,11 +1946,11 @@ public class XPathParser * Predicate ::= '[' PredicateExpr ']' * * - * @throws javax.xml.transform.TransformerException + * @throws TransformerException */ - protected void Predicate() throws javax.xml.transform.TransformerException + protected void Predicate() throws TransformerException { - if (tokenIs('[')) + if (tokenIs(Token.LBRACK)) { countPredicate++; nextToken(); @@ -1957,9 +1965,9 @@ public class XPathParser * PredicateExpr ::= Expr * * - * @throws javax.xml.transform.TransformerException + * @throws TransformerException */ - protected void PredicateExpr() throws javax.xml.transform.TransformerException + protected void PredicateExpr() throws TransformerException { int opPos = m_ops.getOp(OpMap.MAPINDEX_LENGTH); @@ -1979,12 +1987,12 @@ public class XPathParser * Prefix ::= NCName * LocalPart ::= NCName * - * @throws javax.xml.transform.TransformerException + * @throws TransformerException */ - protected void QName() throws javax.xml.transform.TransformerException + protected void QName() throws TransformerException { // Namespace - if(lookahead(':', 1)) + if(lookahead(Token.COLON, 1)) { m_ops.setOp(m_ops.getOp(OpMap.MAPINDEX_LENGTH), m_queueMark - 1); m_ops.setOp(OpMap.MAPINDEX_LENGTH, m_ops.getOp(OpMap.MAPINDEX_LENGTH) + 1); @@ -2026,16 +2034,16 @@ public class XPathParser * | "'" [^']* "'" * * - * @throws javax.xml.transform.TransformerException + * @throws TransformerException */ - protected void Literal() throws javax.xml.transform.TransformerException + protected void Literal() throws TransformerException { int last = m_token.length() - 1; char c0 = m_tokenChar; char cX = m_token.charAt(last); - if (((c0 == '\"') && (cX == '\"')) || ((c0 == '\'') && (cX == '\''))) + if (((c0 == Token.DQ) && (cX == Token.DQ)) || ((c0 == Token.SQ) && (cX == Token.SQ))) { // Mutate the token to remove the quotes and have the XString object @@ -2066,9 +2074,9 @@ public class XPathParser * Number ::= [0-9]+('.'[0-9]+)? | '.'[0-9]+ * * - * @throws javax.xml.transform.TransformerException + * @throws TransformerException */ - protected void Number() throws javax.xml.transform.TransformerException + protected void Number() throws TransformerException { if (null != m_token) @@ -2109,16 +2117,16 @@ public class XPathParser * | Pattern '|' LocationPathPattern * * - * @throws javax.xml.transform.TransformerException + * @throws TransformerException */ - protected void Pattern() throws javax.xml.transform.TransformerException + protected void Pattern() throws TransformerException { while (true) { LocationPathPattern(); - if (tokenIs('|')) + if (tokenIs(Token.VBAR)) { nextToken(); } @@ -2137,9 +2145,9 @@ public class XPathParser * | '//'? RelativePathPattern * * - * @throws javax.xml.transform.TransformerException + * @throws TransformerException */ - protected void LocationPathPattern() throws javax.xml.transform.TransformerException + protected void LocationPathPattern() throws TransformerException { int opPos = m_ops.getOp(OpMap.MAPINDEX_LENGTH); @@ -2152,17 +2160,17 @@ public class XPathParser appendOp(2, OpCodes.OP_LOCATIONPATHPATTERN); - if (lookahead('(', 1) + if (lookahead(Token.LPAREN, 1) && (tokenIs(Keywords.FUNC_ID_STRING) || tokenIs(Keywords.FUNC_KEY_STRING))) { IdKeyPattern(); - if (tokenIs('/')) + if (tokenIs(Token.SLASH)) { nextToken(); - if (tokenIs('/')) + if (tokenIs(Token.SLASH)) { appendOp(4, OpCodes.MATCH_ANY_ANCESTOR); @@ -2180,9 +2188,9 @@ public class XPathParser relativePathStatus = RELATIVE_PATH_REQUIRED; } } - else if (tokenIs('/')) + else if (tokenIs(Token.SLASH)) { - if (lookahead('/', 1)) + if (lookahead(Token.SLASH, 1)) { appendOp(4, OpCodes.MATCH_ANY_ANCESTOR); @@ -2215,7 +2223,7 @@ public class XPathParser if (relativePathStatus != RELATIVE_PATH_NOT_PERMITTED) { - if (!tokenIs('|') && (null != m_token)) + if (!tokenIs(Token.VBAR) && (null != m_token)) { RelativePathPattern(); } @@ -2240,9 +2248,9 @@ public class XPathParser * (Also handle doc()) * * - * @throws javax.xml.transform.TransformerException + * @throws TransformerException */ - protected void IdKeyPattern() throws javax.xml.transform.TransformerException + protected void IdKeyPattern() throws TransformerException { FunctionCall(); } @@ -2253,17 +2261,17 @@ public class XPathParser * | RelativePathPattern '/' StepPattern * | RelativePathPattern '//' StepPattern * - * @throws javax.xml.transform.TransformerException + * @throws TransformerException */ protected void RelativePathPattern() - throws javax.xml.transform.TransformerException + throws TransformerException { // Caller will have consumed any '/' or '//' preceding the // RelativePathPattern, so let StepPattern know it can't begin with a '/' boolean trailingSlashConsumed = StepPattern(false); - while (tokenIs('/')) + while (tokenIs(Token.SLASH)) { nextToken(); @@ -2283,10 +2291,10 @@ public class XPathParser * * @return boolean indicating whether a slash following the step was consumed * - * @throws javax.xml.transform.TransformerException + * @throws TransformerException */ protected boolean StepPattern(boolean isLeadingSlashPermitted) - throws javax.xml.transform.TransformerException + throws TransformerException { return AbbreviatedNodeTestStep(isLeadingSlashPermitted); } @@ -2300,10 +2308,10 @@ public class XPathParser * * @return boolean indicating whether a slash following the step was consumed * - * @throws javax.xml.transform.TransformerException + * @throws TransformerException */ protected boolean AbbreviatedNodeTestStep(boolean isLeadingSlashPermitted) - throws javax.xml.transform.TransformerException + throws TransformerException { int opPos = m_ops.getOp(OpMap.MAPINDEX_LENGTH); @@ -2312,22 +2320,22 @@ public class XPathParser // The next blocks guarantee that a MATCH_XXX will be added. int matchTypePos = -1; - if (tokenIs('@')) + if (tokenIs(Token.AT)) { axesType = OpCodes.MATCH_ATTRIBUTE; appendOp(2, axesType); nextToken(); } - else if (this.lookahead("::", 1)) + else if (this.lookahead(Token.DCOLON, 1)) { - if (tokenIs("attribute")) + if (tokenIs(Token.ATTR)) { axesType = OpCodes.MATCH_ATTRIBUTE; appendOp(2, axesType); } - else if (tokenIs("child")) + else if (tokenIs(Token.CHILD)) { matchTypePos = m_ops.getOp(OpMap.MAPINDEX_LENGTH); axesType = OpCodes.MATCH_IMMEDIATE_ANCESTOR; @@ -2345,7 +2353,7 @@ public class XPathParser nextToken(); nextToken(); } - else if (tokenIs('/')) + else if (tokenIs(Token.SLASH)) { if (!isLeadingSlashPermitted) { @@ -2374,7 +2382,7 @@ public class XPathParser m_ops.setOp(opPos + OpMap.MAPINDEX_LENGTH + 1, m_ops.getOp(OpMap.MAPINDEX_LENGTH) - opPos); - while (tokenIs('[')) + while (tokenIs(Token.LBRACK)) { Predicate(); } @@ -2393,7 +2401,7 @@ public class XPathParser // If current step is on the attribute axis (e.g., "@x//b"), we won't // change the current step, and let following step be marked as // MATCH_ANY_ANCESTOR on next call instead. - if ((matchTypePos > -1) && tokenIs('/') && lookahead('/', 1)) + if ((matchTypePos > -1) && tokenIs(Token.SLASH) && lookahead(Token.SLASH, 1)) { m_ops.setOp(matchTypePos, OpCodes.MATCH_ANY_ANCESTOR); diff --git a/jaxp/src/com/sun/org/apache/xpath/internal/jaxp/XPathFactoryImpl.java b/jaxp/src/com/sun/org/apache/xpath/internal/jaxp/XPathFactoryImpl.java index af9ef866e3..04606a073e 100644 --- a/jaxp/src/com/sun/org/apache/xpath/internal/jaxp/XPathFactoryImpl.java +++ b/jaxp/src/com/sun/org/apache/xpath/internal/jaxp/XPathFactoryImpl.java @@ -30,6 +30,7 @@ import javax.xml.xpath.XPathFactoryConfigurationException; import javax.xml.xpath.XPathFunctionResolver; import javax.xml.xpath.XPathVariableResolver; import jdk.xml.internal.JdkXmlFeatures; +import jdk.xml.internal.XMLSecurityManager; /** * The XPathFactory builds XPaths. @@ -68,6 +69,12 @@ public class XPathFactoryImpl extends XPathFactory { */ private final JdkXmlFeatures _featureManager; + + /** + * The XML security manager + */ + private XMLSecurityManager _xmlSecMgr; + /** * javax.xml.xpath.XPathFactory implementation. */ @@ -78,6 +85,7 @@ public class XPathFactoryImpl extends XPathFactory { _isNotSecureProcessing = false; } _featureManager = new JdkXmlFeatures(!_isNotSecureProcessing); + _xmlSecMgr = new XMLSecurityManager(true); } /** *

Is specified object model supported by this @@ -127,7 +135,7 @@ public class XPathFactoryImpl extends XPathFactory { public javax.xml.xpath.XPath newXPath() { return new com.sun.org.apache.xpath.internal.jaxp.XPathImpl( xPathVariableResolver, xPathFunctionResolver, - !_isNotSecureProcessing, _featureManager ); + !_isNotSecureProcessing, _featureManager, _xmlSecMgr); } /** diff --git a/jaxp/src/com/sun/org/apache/xpath/internal/jaxp/XPathImpl.java b/jaxp/src/com/sun/org/apache/xpath/internal/jaxp/XPathImpl.java index ebf9083ed9..29775c9983 100644 --- a/jaxp/src/com/sun/org/apache/xpath/internal/jaxp/XPathImpl.java +++ b/jaxp/src/com/sun/org/apache/xpath/internal/jaxp/XPathImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. */ /* * Copyright 1999-2004 The Apache Software Foundation. @@ -46,6 +46,7 @@ import javax.xml.parsers.*; import java.io.IOException; import jdk.xml.internal.JdkXmlFeatures; +import jdk.xml.internal.XMLSecurityManager; import jdk.xml.internal.JdkXmlUtils; /** @@ -72,19 +73,23 @@ public class XPathImpl implements javax.xml.xpath.XPath { private boolean featureSecureProcessing = false; private boolean overrideDefaultParser = true; private final JdkXmlFeatures featureManager; + XMLSecurityManager xmlSecMgr; - XPathImpl( XPathVariableResolver vr, XPathFunctionResolver fr ) { - this(vr, fr, false, new JdkXmlFeatures(false)); + XPathImpl(XPathVariableResolver vr, XPathFunctionResolver fr) { + this(vr, fr, false, new JdkXmlFeatures(false), new XMLSecurityManager(true)); } - XPathImpl( XPathVariableResolver vr, XPathFunctionResolver fr, - boolean featureSecureProcessing, JdkXmlFeatures featureManager) { + XPathImpl(XPathVariableResolver vr, XPathFunctionResolver fr, + boolean featureSecureProcessing, JdkXmlFeatures featureManager, + XMLSecurityManager xmlSecMgr) { this.origVariableResolver = this.variableResolver = vr; this.origFunctionResolver = this.functionResolver = fr; this.featureSecureProcessing = featureSecureProcessing; this.featureManager = featureManager; this.overrideDefaultParser = featureManager.getFeature( JdkXmlFeatures.XmlFeature.JDK_OVERRIDE_PARSER); + + this.xmlSecMgr = xmlSecMgr; } /** @@ -187,7 +192,7 @@ public class XPathImpl implements javax.xml.xpath.XPath { private XObject eval(String expression, Object contextItem) throws javax.xml.transform.TransformerException { com.sun.org.apache.xpath.internal.XPath xpath = new com.sun.org.apache.xpath.internal.XPath( expression, - null, prefixResolver, com.sun.org.apache.xpath.internal.XPath.SELECT ); + null, prefixResolver, com.sun.org.apache.xpath.internal.XPath.SELECT, null, null, xmlSecMgr); com.sun.org.apache.xpath.internal.XPathContext xpathSupport = null; if ( functionResolver != null ) { JAXPExtensionsProvider jep = new JAXPExtensionsProvider( @@ -388,7 +393,7 @@ public class XPathImpl implements javax.xml.xpath.XPath { } try { com.sun.org.apache.xpath.internal.XPath xpath = new XPath (expression, null, - prefixResolver, com.sun.org.apache.xpath.internal.XPath.SELECT ); + prefixResolver, com.sun.org.apache.xpath.internal.XPath.SELECT, null, null, xmlSecMgr); // Can have errorListener XPathExpressionImpl ximpl = new XPathExpressionImpl(xpath, prefixResolver, functionResolver, variableResolver, diff --git a/jaxp/src/com/sun/org/apache/xpath/internal/res/XPATHErrorResources.java b/jaxp/src/com/sun/org/apache/xpath/internal/res/XPATHErrorResources.java index 9b29d10c5b..69046c5048 100644 --- a/jaxp/src/com/sun/org/apache/xpath/internal/res/XPATHErrorResources.java +++ b/jaxp/src/com/sun/org/apache/xpath/internal/res/XPATHErrorResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. */ /* * Copyright 1999-2005 The Apache Software Foundation. @@ -32,7 +32,7 @@ import java.util.ListResourceBundle; * Also you need to update the count of messages(MAX_CODE)or * the count of warnings(MAX_WARNING) [ Information purpose only] * @xsl.usage advanced - * @LastModified: May 2019 + * @LastModified: Jan 2022 */ public class XPATHErrorResources extends ListResourceBundle { @@ -322,6 +322,9 @@ public static final String ER_IGNORABLE_WHITESPACE_NOT_HANDLED = public static final String ER_SECUREPROCESSING_FEATURE = "ER_SECUREPROCESSING_FEATURE"; public static final String ER_NULL_XPATH_FUNCTION_RESOLVER = "ER_NULL_XPATH_FUNCTION_RESOLVER"; public static final String ER_NULL_XPATH_VARIABLE_RESOLVER = "ER_NULL_XPATH_VARIABLE_RESOLVER"; + public static final String ER_XPATH_GROUP_LIMIT = "XPATH_GROUP_LIMIT"; + public static final String ER_XPATH_OPERATOR_LIMIT = "XPATH_OPERATOR_LIMIT"; + //END: Keys needed for exception messages of JAXP 1.3 XPath API implementation public static final String WG_LOCALE_NAME_NOT_HANDLED = @@ -833,6 +836,14 @@ public static final String ER_IGNORABLE_WHITESPACE_NOT_HANDLED = { ER_NULL_XPATH_VARIABLE_RESOLVER, "Attempting to set a null XPathVariableResolver:{0}#setXPathVariableResolver(null)"}, + { ER_XPATH_GROUP_LIMIT, + "JAXP0801001: the compiler encountered an XPath expression containing " + + "''{0}'' groups that exceeds the ''{1}'' limit set by ''{2}''."}, + + { ER_XPATH_OPERATOR_LIMIT, + "JAXP0801002: the compiler encountered an XPath expression containing " + + "''{0}'' operators that exceeds the ''{1}'' limit set by ''{2}''."}, + //END: Definitions of error keys used in exception messages of JAXP 1.3 XPath API implementation // Warnings... diff --git a/jaxp/src/jdk/xml/internal/JdkXmlUtils.java b/jaxp/src/jdk/xml/internal/JdkXmlUtils.java index 012fa7711a..6f747c2d56 100644 --- a/jaxp/src/jdk/xml/internal/JdkXmlUtils.java +++ b/jaxp/src/jdk/xml/internal/JdkXmlUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,6 @@ package jdk.xml.internal; -import com.sun.org.apache.xalan.internal.utils.XMLSecurityManager; import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; import com.sun.org.apache.xerces.internal.impl.Constants; import com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl; diff --git a/jaxp/src/jdk/xml/internal/XMLLimitAnalyzer.java b/jaxp/src/jdk/xml/internal/XMLLimitAnalyzer.java new file mode 100644 index 0000000000..cfc3b69ff7 --- /dev/null +++ b/jaxp/src/jdk/xml/internal/XMLLimitAnalyzer.java @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.xml.internal; + +import java.util.Formatter; +import java.util.HashMap; +import java.util.Map; +import jdk.xml.internal.XMLSecurityManager.Limit; +import com.sun.org.apache.xalan.internal.XalanConstants; + + +/** + * A helper for analyzing entity expansion limits + * + */ +public final class XMLLimitAnalyzer { + + /** + * Map old property names with the new ones + */ + public static enum NameMap { + ENTITY_EXPANSION_LIMIT(XalanConstants.SP_ENTITY_EXPANSION_LIMIT, XalanConstants.ENTITY_EXPANSION_LIMIT), + MAX_OCCUR_NODE_LIMIT(XalanConstants.SP_MAX_OCCUR_LIMIT, XalanConstants.MAX_OCCUR_LIMIT), + ELEMENT_ATTRIBUTE_LIMIT(XalanConstants.SP_ELEMENT_ATTRIBUTE_LIMIT, XalanConstants.ELEMENT_ATTRIBUTE_LIMIT); + + final String newName; + final String oldName; + + NameMap(String newName, String oldName) { + this.newName = newName; + this.oldName = oldName; + } + + String getOldName(String newName) { + if (newName.equals(this.newName)) { + return oldName; + } + return null; + } + } + + /** + * Max value accumulated for each property + */ + private final int[] values; + /** + * Names of the entities corresponding to their max values + */ + private final String[] names; + /** + * Total value of accumulated entities + */ + private final int[] totalValue; + + /** + * Maintain values of the top 10 elements in the process of parsing + */ + private final Map[] caches; + + private String entityStart, entityEnd; + /** + * Default constructor. Establishes default values for known security + * vulnerabilities. + */ + @SuppressWarnings({"rawtypes", "unchecked"}) + public XMLLimitAnalyzer() { + values = new int[Limit.values().length]; + totalValue = new int[Limit.values().length]; + names = new String[Limit.values().length]; + caches = new Map[Limit.values().length]; + } + + /** + * Add the value to the current max count for the specified property + * To find the max value of all entities, set no limit + * + * @param limit the type of the property + * @param entityName the name of the entity + * @param value the value of the entity + */ + public void addValue(Limit limit, String entityName, int value) { + addValue(limit.ordinal(), entityName, value); + } + + /** + * Add the value to the current count by the index of the property + * @param index the index of the property + * @param entityName the name of the entity + * @param value the value of the entity + */ + public void addValue(int index, String entityName, int value) { + if (index == Limit.ENTITY_EXPANSION_LIMIT.ordinal() || + index == Limit.MAX_OCCUR_NODE_LIMIT.ordinal() || + index == Limit.ELEMENT_ATTRIBUTE_LIMIT.ordinal() || + index == Limit.TOTAL_ENTITY_SIZE_LIMIT.ordinal() || + index == Limit.ENTITY_REPLACEMENT_LIMIT.ordinal() + ) { + totalValue[index] += value; + return; + } + if (index == Limit.MAX_ELEMENT_DEPTH_LIMIT.ordinal() || + index == Limit.MAX_NAME_LIMIT.ordinal()) { + values[index] = value; + totalValue[index] = value; + return; + } + + Map cache; + if (caches[index] == null) { + cache = new HashMap<>(10); + caches[index] = cache; + } else { + cache = caches[index]; + } + + int accumulatedValue = value; + if (cache.containsKey(entityName)) { + accumulatedValue += cache.get(entityName); + cache.put(entityName, accumulatedValue); + } else { + cache.put(entityName, value); + } + + if (accumulatedValue > values[index]) { + values[index] = accumulatedValue; + names[index] = entityName; + } + + + if (index == Limit.GENEAL_ENTITY_SIZE_LIMIT.ordinal() || + index == Limit.PARAMETER_ENTITY_SIZE_LIMIT.ordinal()) { + totalValue[Limit.TOTAL_ENTITY_SIZE_LIMIT.ordinal()] += value; + } + } + + /** + * Return the value of the current max count for the specified property + * + * @param limit the property + * @return the value of the property + */ + public int getValue(Limit limit) { + return getValue(limit.ordinal()); + } + + public int getValue(int index) { + if (index == Limit.ENTITY_REPLACEMENT_LIMIT.ordinal()) { + return totalValue[index]; + } + return values[index]; + } + /** + * Return the total value accumulated so far + * + * @param limit the property + * @return the accumulated value of the property + */ + public int getTotalValue(Limit limit) { + return totalValue[limit.ordinal()]; + } + + public int getTotalValue(int index) { + return totalValue[index]; + } + /** + * Return the current max value (count or length) by the index of a property + * @param index the index of a property + * @return count of a property + */ + public int getValueByIndex(int index) { + return values[index]; + } + + public void startEntity(String name) { + entityStart = name; + } + + public boolean isTracking(String name) { + if (entityStart == null) { + return false; + } + return entityStart.equals(name); + } + /** + * Stop tracking the entity + * @param limit the limit property + * @param name the name of an entity + */ + public void endEntity(Limit limit, String name) { + entityStart = ""; + Map cache = caches[limit.ordinal()]; + if (cache != null) { + cache.remove(name); + } + } + + /** + * Resets the current value of the specified limit. + * @param limit The limit to be reset. + */ + public void reset(Limit limit) { + if (limit.ordinal() == Limit.TOTAL_ENTITY_SIZE_LIMIT.ordinal()) { + totalValue[limit.ordinal()] = 0; + } else if (limit.ordinal() == Limit.GENEAL_ENTITY_SIZE_LIMIT.ordinal()) { + names[limit.ordinal()] = null; + values[limit.ordinal()] = 0; + caches[limit.ordinal()] = null; + totalValue[limit.ordinal()] = 0; + } + } + + public void debugPrint(XMLSecurityManager securityManager) { + Formatter formatter = new Formatter(); + System.out.println(formatter.format("%30s %15s %15s %15s %30s", + "Property","Limit","Total size","Size","Entity Name")); + + for (Limit limit : Limit.values()) { + formatter = new Formatter(); + System.out.println(formatter.format("%30s %15d %15d %15d %30s", + limit.name(), + securityManager.getLimit(limit), + totalValue[limit.ordinal()], + values[limit.ordinal()], + names[limit.ordinal()])); + } + } +} diff --git a/jaxp/src/com/sun/org/apache/xalan/internal/utils/XMLSecurityManager.java b/jaxp/src/jdk/xml/internal/XMLSecurityManager.java similarity index 67% rename from jaxp/src/com/sun/org/apache/xalan/internal/utils/XMLSecurityManager.java rename to jaxp/src/jdk/xml/internal/XMLSecurityManager.java index e382b0d0a7..c9436a1ebd 100644 --- a/jaxp/src/com/sun/org/apache/xalan/internal/utils/XMLSecurityManager.java +++ b/jaxp/src/jdk/xml/internal/XMLSecurityManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,19 +23,17 @@ * questions. */ -package com.sun.org.apache.xalan.internal.utils; +package jdk.xml.internal; -import com.sun.org.apache.xalan.internal.XalanConstants; +import com.sun.org.apache.xerces.internal.util.SecurityManager; import java.util.concurrent.CopyOnWriteArrayList; +import com.sun.org.apache.xalan.internal.XalanConstants; import org.xml.sax.SAXException; /** - * This class is not the same as that in Xerces. It is used to manage the - * state of corresponding Xerces properties and pass the values over to - * the Xerces Security Manager. * - * @author Joe Wang Oracle Corp. + * This class manages standard and implementation-specific limitations. * */ public final class XMLSecurityManager { @@ -66,38 +64,47 @@ public final class XMLSecurityManager { * Limits managed by the security manager */ public static enum Limit { - ENTITY_EXPANSION_LIMIT("EntityExpansionLimit", XalanConstants.JDK_ENTITY_EXPANSION_LIMIT, - XalanConstants.SP_ENTITY_EXPANSION_LIMIT, 0, 64000), + XalanConstants.SP_ENTITY_EXPANSION_LIMIT, 0, 64000, Processor.PARSER), MAX_OCCUR_NODE_LIMIT("MaxOccurLimit", XalanConstants.JDK_MAX_OCCUR_LIMIT, - XalanConstants.SP_MAX_OCCUR_LIMIT, 0, 5000), + XalanConstants.SP_MAX_OCCUR_LIMIT, 0, 5000, Processor.PARSER), ELEMENT_ATTRIBUTE_LIMIT("ElementAttributeLimit", XalanConstants.JDK_ELEMENT_ATTRIBUTE_LIMIT, - XalanConstants.SP_ELEMENT_ATTRIBUTE_LIMIT, 0, 10000), + XalanConstants.SP_ELEMENT_ATTRIBUTE_LIMIT, 0, 10000, Processor.PARSER), TOTAL_ENTITY_SIZE_LIMIT("TotalEntitySizeLimit", XalanConstants.JDK_TOTAL_ENTITY_SIZE_LIMIT, - XalanConstants.SP_TOTAL_ENTITY_SIZE_LIMIT, 0, 50000000), + XalanConstants.SP_TOTAL_ENTITY_SIZE_LIMIT, 0, 50000000, Processor.PARSER), GENEAL_ENTITY_SIZE_LIMIT("MaxEntitySizeLimit", XalanConstants.JDK_GENEAL_ENTITY_SIZE_LIMIT, - XalanConstants.SP_GENEAL_ENTITY_SIZE_LIMIT, 0, 0), + XalanConstants.SP_GENEAL_ENTITY_SIZE_LIMIT, 0, 0, Processor.PARSER), PARAMETER_ENTITY_SIZE_LIMIT("MaxEntitySizeLimit", XalanConstants.JDK_PARAMETER_ENTITY_SIZE_LIMIT, - XalanConstants.SP_PARAMETER_ENTITY_SIZE_LIMIT, 0, 1000000), + XalanConstants.SP_PARAMETER_ENTITY_SIZE_LIMIT, 0, 1000000, Processor.PARSER), MAX_ELEMENT_DEPTH_LIMIT("MaxElementDepthLimit", XalanConstants.JDK_MAX_ELEMENT_DEPTH, - XalanConstants.SP_MAX_ELEMENT_DEPTH, 0, 0), + XalanConstants.SP_MAX_ELEMENT_DEPTH, 0, 0, Processor.PARSER), MAX_NAME_LIMIT("MaxXMLNameLimit", XalanConstants.JDK_XML_NAME_LIMIT, - XalanConstants.SP_XML_NAME_LIMIT, 1000, 1000), + XalanConstants.SP_XML_NAME_LIMIT, 1000, 1000, Processor.PARSER), ENTITY_REPLACEMENT_LIMIT("EntityReplacementLimit", XalanConstants.JDK_ENTITY_REPLACEMENT_LIMIT, - XalanConstants.SP_ENTITY_REPLACEMENT_LIMIT, 0, 3000000); + XalanConstants.SP_ENTITY_REPLACEMENT_LIMIT, 0, 3000000, Processor.PARSER), + XPATH_GROUP_LIMIT("XPathGroupLimit", XalanConstants.XPATH_GROUP_LIMIT, + XalanConstants.XPATH_GROUP_LIMIT, 10, 10, Processor.XPATH), + XPATH_OP_LIMIT("XPathExprOpLimit", XalanConstants.XPATH_OP_LIMIT, + XalanConstants.XPATH_OP_LIMIT, 100, 100, Processor.XPATH), + XPATH_TOTALOP_LIMIT("XPathTotalOpLimit", XalanConstants.XPATH_TOTALOP_LIMIT, + XalanConstants.XPATH_TOTALOP_LIMIT, 10000, 10000, Processor.XPATH) + ; final String key; final String apiProperty; final String systemProperty; final int defaultValue; final int secureValue; + final Processor processor; - Limit(String key, String apiProperty, String systemProperty, int value, int secureValue) { + Limit(String key, String apiProperty, String systemProperty, int value, + int secureValue, Processor processor) { this.key = key; this.apiProperty = apiProperty; this.systemProperty = systemProperty; this.defaultValue = value; this.secureValue = secureValue; + this.processor = processor; } public boolean equalsAPIPropertyName(String propertyName) { @@ -124,6 +131,10 @@ public final class XMLSecurityManager { return defaultValue; } + public boolean isSupported(Processor p) { + return processor == p; + } + int secureValue() { return secureValue; } @@ -134,12 +145,9 @@ public final class XMLSecurityManager { */ public static enum NameMap { - ENTITY_EXPANSION_LIMIT(XalanConstants.SP_ENTITY_EXPANSION_LIMIT, - XalanConstants.ENTITY_EXPANSION_LIMIT), - MAX_OCCUR_NODE_LIMIT(XalanConstants.SP_MAX_OCCUR_LIMIT, - XalanConstants.MAX_OCCUR_LIMIT), - ELEMENT_ATTRIBUTE_LIMIT(XalanConstants.SP_ELEMENT_ATTRIBUTE_LIMIT, - XalanConstants.ELEMENT_ATTRIBUTE_LIMIT); + ENTITY_EXPANSION_LIMIT(XalanConstants.SP_ENTITY_EXPANSION_LIMIT, XalanConstants.ENTITY_EXPANSION_LIMIT), + MAX_OCCUR_NODE_LIMIT(XalanConstants.SP_MAX_OCCUR_LIMIT, XalanConstants.MAX_OCCUR_LIMIT), + ELEMENT_ATTRIBUTE_LIMIT(XalanConstants.SP_ELEMENT_ATTRIBUTE_LIMIT, XalanConstants.ELEMENT_ATTRIBUTE_LIMIT); final String newName; final String oldName; @@ -155,14 +163,32 @@ public final class XMLSecurityManager { return null; } } + + /** + * Supported processors + */ + public static enum Processor { + PARSER, + XPATH, + } + + private static final int NO_LIMIT = 0; + /** * Values of the properties */ private final int[] values; + /** * States of the settings for each property */ private State[] states; + + /** + * Flag indicating if secure processing is set + */ + boolean secureProcessing; + /** * States that determine if properties are set explicitly */ @@ -192,9 +218,10 @@ public final class XMLSecurityManager { values = new int[Limit.values().length]; states = new State[Limit.values().length]; isSet = new boolean[Limit.values().length]; + this.secureProcessing = secureProcessing; for (Limit limit : Limit.values()) { if (secureProcessing) { - values[limit.ordinal()] = limit.secureValue(); + values[limit.ordinal()] = limit.secureValue; states[limit.ordinal()] = State.FSP; } else { values[limit.ordinal()] = limit.defaultValue(); @@ -209,6 +236,7 @@ public final class XMLSecurityManager { * Setting FEATURE_SECURE_PROCESSING explicitly */ public void setSecureProcessing(boolean secure) { + secureProcessing = secure; for (Limit limit : Limit.values()) { if (secure) { setLimit(limit.ordinal(), State.FSP, limit.secureValue()); @@ -218,6 +246,14 @@ public final class XMLSecurityManager { } } + /** + * Return the state of secure processing + * @return the state of secure processing + */ + public boolean isSecureProcessing() { + return secureProcessing; + } + /** * Set limit by property name and state * @param propertyName property name @@ -255,7 +291,6 @@ public final class XMLSecurityManager { */ public void setLimit(int index, State state, Object value) { if (index == indexEntityCountInfo) { - //if it's explicitly set, it's treated as yes no matter the value printEntityCountInfo = (String)value; } else { int temp = 0; @@ -289,9 +324,8 @@ public final class XMLSecurityManager { } } - /** - * Return the value of the specified property. + * Return the value of the specified property * * @param propertyName the property name * @return the value of the property as a string. If a property is managed @@ -305,17 +339,6 @@ public final class XMLSecurityManager { return null; } - - /** - * Return the value of a property by its ordinal - * - * @param limit the property - * @return value of a property - */ - public String getLimitValueAsString(Limit limit) { - return Integer.toString(values[limit.ordinal()]); - } - /** * Return the value of the specified property * @@ -329,14 +352,15 @@ public final class XMLSecurityManager { /** * Return the value of a property by its ordinal * - * @param index the index of a property + * @param limit the property * @return value of a property */ - public int getLimitByIndex(int index) { - return values[index]; + public String getLimitValueAsString(Limit limit) { + return Integer.toString(values[limit.ordinal()]); } + /** - * Return the value of a property by its index + * Return the value of a property by its ordinal * * @param index the index of a property * @return limit of a property as a string @@ -348,6 +372,7 @@ public final class XMLSecurityManager { return Integer.toString(values[index]); } + /** * Return the state of the limit property * @@ -388,6 +413,85 @@ public final class XMLSecurityManager { return -1; } + /** + * Check if there's no limit defined by the Security Manager + * @param limit + * @return + */ + public boolean isNoLimit(int limit) { + return limit == NO_LIMIT; + } + /** + * Check if the size (length or count) of the specified limit property is + * over the limit + * + * @param limit the type of the limit property + * @param entityName the name of the entity + * @param size the size (count or length) of the entity + * @return true if the size is over the limit, false otherwise + */ + public boolean isOverLimit(Limit limit, String entityName, int size, + XMLLimitAnalyzer limitAnalyzer) { + return isOverLimit(limit.ordinal(), entityName, size, limitAnalyzer); + } + + /** + * Check if the value (length or count) of the specified limit property is + * over the limit + * + * @param index the index of the limit property + * @param entityName the name of the entity + * @param size the size (count or length) of the entity + * @return true if the size is over the limit, false otherwise + */ + public boolean isOverLimit(int index, String entityName, int size, + XMLLimitAnalyzer limitAnalyzer) { + if (values[index] == NO_LIMIT) { + return false; + } + if (size > values[index]) { + limitAnalyzer.addValue(index, entityName, size); + return true; + } + return false; + } + + /** + * Check against cumulated value + * + * @param limit the type of the limit property + * @param size the size (count or length) of the entity + * @return true if the size is over the limit, false otherwise + */ + public boolean isOverLimit(Limit limit, XMLLimitAnalyzer limitAnalyzer) { + return isOverLimit(limit.ordinal(), limitAnalyzer); + } + + public boolean isOverLimit(int index, XMLLimitAnalyzer limitAnalyzer) { + if (values[index] == NO_LIMIT) { + return false; + } + + if (index == Limit.ELEMENT_ATTRIBUTE_LIMIT.ordinal() || + index == Limit.ENTITY_EXPANSION_LIMIT.ordinal() || + index == Limit.TOTAL_ENTITY_SIZE_LIMIT.ordinal() || + index == Limit.ENTITY_REPLACEMENT_LIMIT.ordinal() || + index == Limit.MAX_ELEMENT_DEPTH_LIMIT.ordinal() || + index == Limit.MAX_NAME_LIMIT.ordinal() + ) { + return (limitAnalyzer.getTotalValue(index) > values[index]); + } else { + return (limitAnalyzer.getValue(index) > values[index]); + } + } + + public void debugPrint(XMLLimitAnalyzer limitAnalyzer) { + if (printEntityCountInfo.equals(XalanConstants.JDK_YES)) { + limitAnalyzer.debugPrint(this); + } + } + + /** * Indicate if a property is set explicitly * @param index @@ -400,6 +504,7 @@ public final class XMLSecurityManager { public boolean printEntityCountInfo() { return printEntityCountInfo.equals(XalanConstants.JDK_YES); } + /** * Read from system properties, or those in jaxp.properties */ @@ -463,4 +568,37 @@ public final class XMLSecurityManager { } return false; } + + + /** + * Convert a value set through setProperty to XMLSecurityManager. + * If the value is an instance of XMLSecurityManager, use it to override the default; + * If the value is an old SecurityManager, convert to the new XMLSecurityManager. + * + * @param value user specified security manager + * @param securityManager an instance of XMLSecurityManager + * @return an instance of the new security manager XMLSecurityManager + */ + public static XMLSecurityManager convert(Object value, XMLSecurityManager securityManager) { + if (value == null) { + if (securityManager == null) { + securityManager = new XMLSecurityManager(true); + } + return securityManager; + } + if (value instanceof XMLSecurityManager) { + return (XMLSecurityManager)value; + } else { + if (securityManager == null) { + securityManager = new XMLSecurityManager(true); + } + if (value instanceof SecurityManager) { + SecurityManager origSM = (SecurityManager)value; + securityManager.setLimit(Limit.MAX_OCCUR_NODE_LIMIT, State.APIPROPERTY, origSM.getMaxOccurNodeLimit()); + securityManager.setLimit(Limit.ENTITY_EXPANSION_LIMIT, State.APIPROPERTY, origSM.getEntityExpansionLimit()); + securityManager.setLimit(Limit.ELEMENT_ATTRIBUTE_LIMIT, State.APIPROPERTY, origSM.getElementAttrLimit()); + } + return securityManager; + } + } }