1 /*
   2  * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
   3  * @LastModified: Oct 2017
   4  */
   5 /**
   6  * Licensed to the Apache Software Foundation (ASF) under one
   7  * or more contributor license agreements. See the NOTICE file
   8  * distributed with this work for additional information
   9  * regarding copyright ownership. The ASF licenses this file
  10  * to you under the Apache License, Version 2.0 (the
  11  * "License"); you may not use this file except in compliance
  12  * with the License. You may obtain a copy of the License at
  13  *
  14  * http://www.apache.org/licenses/LICENSE-2.0
  15  *
  16  * Unless required by applicable law or agreed to in writing,
  17  * software distributed under the License is distributed on an
  18  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  19  * KIND, either express or implied. See the License for the
  20  * specific language governing permissions and limitations
  21  * under the License.
  22  */
  23 
  24 package com.sun.org.apache.xpath.internal.compiler;
  25 
  26 import com.sun.org.apache.xpath.internal.functions.Function;
  27 import java.lang.reflect.InvocationTargetException;
  28 import java.util.HashMap;
  29 import java.util.Map;
  30 import javax.xml.transform.TransformerException;
  31 
  32 /**
  33  * The function table for XPath.
  34  */
  35 public class FunctionTable
  36 {
  37 
  38   /** The 'current()' id. */
  39   public static final int FUNC_CURRENT = 0;
  40 
  41   /** The 'last()' id. */
  42   public static final int FUNC_LAST = 1;
  43 
  44   /** The 'position()' id. */
  45   public static final int FUNC_POSITION = 2;
  46 
  47   /** The 'count()' id. */
  48   public static final int FUNC_COUNT = 3;
  49 
  50   /** The 'id()' id. */
  51   public static final int FUNC_ID = 4;
  52 
  53   /** The 'key()' id (XSLT). */
  54   public static final int FUNC_KEY = 5;
  55 
  56   /** The 'local-name()' id. */
  57   public static final int FUNC_LOCAL_PART = 7;
  58 
  59   /** The 'namespace-uri()' id. */
  60   public static final int FUNC_NAMESPACE = 8;
  61 
  62   /** The 'name()' id. */
  63   public static final int FUNC_QNAME = 9;
  64 
  65   /** The 'generate-id()' id. */
  66   public static final int FUNC_GENERATE_ID = 10;
  67 
  68   /** The 'not()' id. */
  69   public static final int FUNC_NOT = 11;
  70 
  71   /** The 'true()' id. */
  72   public static final int FUNC_TRUE = 12;
  73 
  74   /** The 'false()' id. */
  75   public static final int FUNC_FALSE = 13;
  76 
  77   /** The 'boolean()' id. */
  78   public static final int FUNC_BOOLEAN = 14;
  79 
  80   /** The 'number()' id. */
  81   public static final int FUNC_NUMBER = 15;
  82 
  83   /** The 'floor()' id. */
  84   public static final int FUNC_FLOOR = 16;
  85 
  86   /** The 'ceiling()' id. */
  87   public static final int FUNC_CEILING = 17;
  88 
  89   /** The 'round()' id. */
  90   public static final int FUNC_ROUND = 18;
  91 
  92   /** The 'sum()' id. */
  93   public static final int FUNC_SUM = 19;
  94 
  95   /** The 'string()' id. */
  96   public static final int FUNC_STRING = 20;
  97 
  98   /** The 'starts-with()' id. */
  99   public static final int FUNC_STARTS_WITH = 21;
 100 
 101   /** The 'contains()' id. */
 102   public static final int FUNC_CONTAINS = 22;
 103 
 104   /** The 'substring-before()' id. */
 105   public static final int FUNC_SUBSTRING_BEFORE = 23;
 106 
 107   /** The 'substring-after()' id. */
 108   public static final int FUNC_SUBSTRING_AFTER = 24;
 109 
 110   /** The 'normalize-space()' id. */
 111   public static final int FUNC_NORMALIZE_SPACE = 25;
 112 
 113   /** The 'translate()' id. */
 114   public static final int FUNC_TRANSLATE = 26;
 115 
 116   /** The 'concat()' id. */
 117   public static final int FUNC_CONCAT = 27;
 118 
 119   /** The 'substring()' id. */
 120   public static final int FUNC_SUBSTRING = 29;
 121 
 122   /** The 'string-length()' id. */
 123   public static final int FUNC_STRING_LENGTH = 30;
 124 
 125   /** The 'system-property()' id. */
 126   public static final int FUNC_SYSTEM_PROPERTY = 31;
 127 
 128   /** The 'lang()' id. */
 129   public static final int FUNC_LANG = 32;
 130 
 131   /** The 'function-available()' id (XSLT). */
 132   public static final int FUNC_EXT_FUNCTION_AVAILABLE = 33;
 133 
 134   /** The 'element-available()' id (XSLT). */
 135   public static final int FUNC_EXT_ELEM_AVAILABLE = 34;
 136 
 137   /** The 'unparsed-entity-uri()' id (XSLT). */
 138   public static final int FUNC_UNPARSED_ENTITY_URI = 36;
 139 
 140   /** The 'here()' id (XML Signature). */
 141   public static final int FUNC_HERE = 37;
 142 
 143   // Proprietary
 144 
 145   /** The 'document-location()' id (Proprietary). */
 146   public static final int FUNC_DOCLOCATION = 35;
 147 
 148   /**
 149    * The function table.
 150    */
 151   private static Class<?> m_functions[];
 152 
 153   /** Table of function name to function ID associations. */
 154   private static final Map<String, Integer> m_functionID = new HashMap<>();
 155 
 156   /**
 157    * The function table contains customized functions
 158    */
 159   private Class<?> m_functions_customer[] = new Class<?>[NUM_ALLOWABLE_ADDINS];
 160 
 161   /**
 162    * Table of function name to function ID associations for customized functions
 163    */
 164   private Map<String, Integer> m_functionID_customer = new HashMap<>();
 165 
 166   /**
 167    * Number of built in functions.  Be sure to update this as
 168    * built-in functions are added.
 169    */
 170   private static final int NUM_BUILT_IN_FUNCS = 38;
 171 
 172   /**
 173    * Number of built-in functions that may be added.
 174    */
 175   private static final int NUM_ALLOWABLE_ADDINS = 30;
 176 
 177   /**
 178    * The index to the next free function index.
 179    */
 180   private int m_funcNextFreeIndex = NUM_BUILT_IN_FUNCS;
 181 
 182   static
 183   {
 184     m_functions = new Class<?>[NUM_BUILT_IN_FUNCS];
 185     m_functions[FUNC_CURRENT] = com.sun.org.apache.xpath.internal.functions.FuncCurrent.class;
 186     m_functions[FUNC_LAST] = com.sun.org.apache.xpath.internal.functions.FuncLast.class;
 187     m_functions[FUNC_POSITION] = com.sun.org.apache.xpath.internal.functions.FuncPosition.class;
 188     m_functions[FUNC_COUNT] = com.sun.org.apache.xpath.internal.functions.FuncCount.class;
 189     m_functions[FUNC_ID] = com.sun.org.apache.xpath.internal.functions.FuncId.class;
 190     // J2SE does not support Xalan interpretive
 191     // m_functions[FUNC_KEY] =
 192     //   com.sun.org.apache.xalan.internal.templates.FuncKey.class;
 193     m_functions[FUNC_LOCAL_PART] =
 194       com.sun.org.apache.xpath.internal.functions.FuncLocalPart.class;
 195     m_functions[FUNC_NAMESPACE] =
 196       com.sun.org.apache.xpath.internal.functions.FuncNamespace.class;
 197     m_functions[FUNC_QNAME] = com.sun.org.apache.xpath.internal.functions.FuncQname.class;
 198     m_functions[FUNC_GENERATE_ID] =
 199       com.sun.org.apache.xpath.internal.functions.FuncGenerateId.class;
 200     m_functions[FUNC_NOT] = com.sun.org.apache.xpath.internal.functions.FuncNot.class;
 201     m_functions[FUNC_TRUE] = com.sun.org.apache.xpath.internal.functions.FuncTrue.class;
 202     m_functions[FUNC_FALSE] = com.sun.org.apache.xpath.internal.functions.FuncFalse.class;
 203     m_functions[FUNC_BOOLEAN] = com.sun.org.apache.xpath.internal.functions.FuncBoolean.class;
 204     m_functions[FUNC_LANG] = com.sun.org.apache.xpath.internal.functions.FuncLang.class;
 205     m_functions[FUNC_NUMBER] = com.sun.org.apache.xpath.internal.functions.FuncNumber.class;
 206     m_functions[FUNC_FLOOR] = com.sun.org.apache.xpath.internal.functions.FuncFloor.class;
 207     m_functions[FUNC_CEILING] = com.sun.org.apache.xpath.internal.functions.FuncCeiling.class;
 208     m_functions[FUNC_ROUND] = com.sun.org.apache.xpath.internal.functions.FuncRound.class;
 209     m_functions[FUNC_SUM] = com.sun.org.apache.xpath.internal.functions.FuncSum.class;
 210     m_functions[FUNC_STRING] = com.sun.org.apache.xpath.internal.functions.FuncString.class;
 211     m_functions[FUNC_STARTS_WITH] =
 212       com.sun.org.apache.xpath.internal.functions.FuncStartsWith.class;
 213     m_functions[FUNC_CONTAINS] = com.sun.org.apache.xpath.internal.functions.FuncContains.class;
 214     m_functions[FUNC_SUBSTRING_BEFORE] =
 215       com.sun.org.apache.xpath.internal.functions.FuncSubstringBefore.class;
 216     m_functions[FUNC_SUBSTRING_AFTER] =
 217       com.sun.org.apache.xpath.internal.functions.FuncSubstringAfter.class;
 218     m_functions[FUNC_NORMALIZE_SPACE] =
 219       com.sun.org.apache.xpath.internal.functions.FuncNormalizeSpace.class;
 220     m_functions[FUNC_TRANSLATE] =
 221       com.sun.org.apache.xpath.internal.functions.FuncTranslate.class;
 222     m_functions[FUNC_CONCAT] = com.sun.org.apache.xpath.internal.functions.FuncConcat.class;
 223     m_functions[FUNC_SYSTEM_PROPERTY] =
 224       com.sun.org.apache.xpath.internal.functions.FuncSystemProperty.class;
 225     m_functions[FUNC_EXT_FUNCTION_AVAILABLE] =
 226       com.sun.org.apache.xpath.internal.functions.FuncExtFunctionAvailable.class;
 227     m_functions[FUNC_EXT_ELEM_AVAILABLE] =
 228       com.sun.org.apache.xpath.internal.functions.FuncExtElementAvailable.class;
 229     m_functions[FUNC_SUBSTRING] =
 230       com.sun.org.apache.xpath.internal.functions.FuncSubstring.class;
 231     m_functions[FUNC_STRING_LENGTH] =
 232       com.sun.org.apache.xpath.internal.functions.FuncStringLength.class;
 233     m_functions[FUNC_DOCLOCATION] =
 234       com.sun.org.apache.xpath.internal.functions.FuncDoclocation.class;
 235     m_functions[FUNC_UNPARSED_ENTITY_URI] =
 236       com.sun.org.apache.xpath.internal.functions.FuncUnparsedEntityURI.class;
 237     m_functions[FUNC_HERE] =
 238       com.sun.org.apache.xpath.internal.functions.FuncHere.class;
 239   }
 240 
 241   static{
 242           m_functionID.put(Keywords.FUNC_CURRENT_STRING,
 243                           FunctionTable.FUNC_CURRENT);
 244           m_functionID.put(Keywords.FUNC_LAST_STRING,
 245                           FunctionTable.FUNC_LAST);
 246           m_functionID.put(Keywords.FUNC_POSITION_STRING,
 247                           FunctionTable.FUNC_POSITION);
 248           m_functionID.put(Keywords.FUNC_COUNT_STRING,
 249                           FunctionTable.FUNC_COUNT);
 250           m_functionID.put(Keywords.FUNC_ID_STRING,
 251                           FunctionTable.FUNC_ID);
 252           m_functionID.put(Keywords.FUNC_KEY_STRING,
 253                           FunctionTable.FUNC_KEY);
 254           m_functionID.put(Keywords.FUNC_LOCAL_PART_STRING,
 255                           FunctionTable.FUNC_LOCAL_PART);
 256           m_functionID.put(Keywords.FUNC_NAMESPACE_STRING,
 257                           FunctionTable.FUNC_NAMESPACE);
 258           m_functionID.put(Keywords.FUNC_NAME_STRING,
 259                           FunctionTable.FUNC_QNAME);
 260           m_functionID.put(Keywords.FUNC_GENERATE_ID_STRING,
 261                           FunctionTable.FUNC_GENERATE_ID);
 262           m_functionID.put(Keywords.FUNC_NOT_STRING,
 263                           FunctionTable.FUNC_NOT);
 264           m_functionID.put(Keywords.FUNC_TRUE_STRING,
 265                           FunctionTable.FUNC_TRUE);
 266           m_functionID.put(Keywords.FUNC_FALSE_STRING,
 267                           FunctionTable.FUNC_FALSE);
 268           m_functionID.put(Keywords.FUNC_BOOLEAN_STRING,
 269                           FunctionTable.FUNC_BOOLEAN);
 270           m_functionID.put(Keywords.FUNC_LANG_STRING,
 271                           FunctionTable.FUNC_LANG);
 272           m_functionID.put(Keywords.FUNC_NUMBER_STRING,
 273                           FunctionTable.FUNC_NUMBER);
 274           m_functionID.put(Keywords.FUNC_FLOOR_STRING,
 275                           FunctionTable.FUNC_FLOOR);
 276           m_functionID.put(Keywords.FUNC_CEILING_STRING,
 277                           FunctionTable.FUNC_CEILING);
 278           m_functionID.put(Keywords.FUNC_ROUND_STRING,
 279                           FunctionTable.FUNC_ROUND);
 280           m_functionID.put(Keywords.FUNC_SUM_STRING,
 281                           FunctionTable.FUNC_SUM);
 282           m_functionID.put(Keywords.FUNC_STRING_STRING,
 283                           FunctionTable.FUNC_STRING);
 284           m_functionID.put(Keywords.FUNC_STARTS_WITH_STRING,
 285                           FunctionTable.FUNC_STARTS_WITH);
 286           m_functionID.put(Keywords.FUNC_CONTAINS_STRING,
 287                           FunctionTable.FUNC_CONTAINS);
 288           m_functionID.put(Keywords.FUNC_SUBSTRING_BEFORE_STRING,
 289                           FunctionTable.FUNC_SUBSTRING_BEFORE);
 290           m_functionID.put(Keywords.FUNC_SUBSTRING_AFTER_STRING,
 291                           FunctionTable.FUNC_SUBSTRING_AFTER);
 292           m_functionID.put(Keywords.FUNC_NORMALIZE_SPACE_STRING,
 293                           FunctionTable.FUNC_NORMALIZE_SPACE);
 294           m_functionID.put(Keywords.FUNC_TRANSLATE_STRING,
 295                           FunctionTable.FUNC_TRANSLATE);
 296           m_functionID.put(Keywords.FUNC_CONCAT_STRING,
 297                           FunctionTable.FUNC_CONCAT);
 298           m_functionID.put(Keywords.FUNC_SYSTEM_PROPERTY_STRING,
 299                           FunctionTable.FUNC_SYSTEM_PROPERTY);
 300           m_functionID.put(Keywords.FUNC_EXT_FUNCTION_AVAILABLE_STRING,
 301                         FunctionTable.FUNC_EXT_FUNCTION_AVAILABLE);
 302           m_functionID.put(Keywords.FUNC_EXT_ELEM_AVAILABLE_STRING,
 303                           FunctionTable.FUNC_EXT_ELEM_AVAILABLE);
 304           m_functionID.put(Keywords.FUNC_SUBSTRING_STRING,
 305                           FunctionTable.FUNC_SUBSTRING);
 306           m_functionID.put(Keywords.FUNC_STRING_LENGTH_STRING,
 307                           FunctionTable.FUNC_STRING_LENGTH);
 308           m_functionID.put(Keywords.FUNC_UNPARSED_ENTITY_URI_STRING,
 309                           FunctionTable.FUNC_UNPARSED_ENTITY_URI);
 310           m_functionID.put(Keywords.FUNC_DOCLOCATION_STRING,
 311                           FunctionTable.FUNC_DOCLOCATION);
 312           m_functionID.put(Keywords.FUNC_HERE_STRING,
 313                           FunctionTable.FUNC_HERE);
 314   }
 315 
 316   public FunctionTable(){
 317   }
 318 
 319   /**
 320    * Return the name of the a function in the static table. Needed to avoid
 321    * making the table publicly available.
 322    */
 323   String getFunctionName(int funcID) {
 324       if (funcID < NUM_BUILT_IN_FUNCS) return m_functions[funcID].getName();
 325       else return m_functions_customer[funcID - NUM_BUILT_IN_FUNCS].getName();
 326   }
 327 
 328   /**
 329    * Obtain a new Function object from a function ID.
 330    *
 331    * @param which  The function ID, which may correspond to one of the FUNC_XXX
 332    *    values found in {@link com.sun.org.apache.xpath.internal.compiler.FunctionTable}, but may
 333    *    be a value installed by an external module.
 334    *
 335    * @return a a new Function instance.
 336    *
 337    * @throws javax.xml.transform.TransformerException if ClassNotFoundException,
 338    *    IllegalAccessException, or InstantiationException is thrown.
 339    */
 340   Function getFunction(int which)
 341           throws javax.xml.transform.TransformerException
 342   {
 343           try{
 344               if (which < NUM_BUILT_IN_FUNCS) {
 345                   return (Function) m_functions[which].getConstructor().newInstance();
 346               } else {
 347                   Class<?> c =  m_functions_customer[which-NUM_BUILT_IN_FUNCS];
 348                   return (Function) c.getConstructor().newInstance();
 349               }
 350           }catch (InstantiationException | IllegalAccessException | SecurityException |
 351               IllegalArgumentException | InvocationTargetException | NoSuchMethodException ex){
 352               throw new TransformerException(ex.getMessage());
 353           }
 354   }
 355 
 356   /**
 357    * Obtain a function ID from a given function name
 358    * @param key the function name in a java.lang.String format.
 359    * @return a function ID, which may correspond to one of the FUNC_XXX values
 360    * found in {@link com.sun.org.apache.xpath.internal.compiler.FunctionTable}, but may be a
 361    * value installed by an external module.
 362    */
 363   Integer getFunctionID(String key){
 364           Integer id = m_functionID_customer.get(key);
 365           if (null == id) id = m_functionID.get(key);
 366           return id;
 367   }
 368 
 369   /**
 370    * Install a built-in function.
 371    * @param name The unqualified name of the function, must not be null
 372    * @param func A Implementation of an XPath Function object.
 373    * @return the position of the function in the internal index.
 374    */
 375   public int installFunction(String name, Class<?> func)
 376   {
 377 
 378     int funcIndex;
 379     Integer funcIndexObj = getFunctionID(name);
 380 
 381     if (func != null && !Function.class.isAssignableFrom(func)) {
 382         throw new ClassCastException(func.getName()
 383                   + " cannot be cast to "
 384                   + Function.class.getName());
 385     }
 386 
 387     if (null != funcIndexObj)
 388     {
 389       funcIndex = funcIndexObj;
 390 
 391       if (funcIndex < NUM_BUILT_IN_FUNCS){
 392               funcIndex = m_funcNextFreeIndex++;
 393               m_functionID_customer.put(name, funcIndex);
 394       }
 395       m_functions_customer[funcIndex - NUM_BUILT_IN_FUNCS] = func;
 396     }
 397     else
 398     {
 399             funcIndex = m_funcNextFreeIndex++;
 400             m_functions_customer[funcIndex-NUM_BUILT_IN_FUNCS] = func;
 401             m_functionID_customer.put(name, funcIndex);
 402     }
 403     return funcIndex;
 404   }
 405 
 406   /**
 407    * Tell if a built-in, non-namespaced function is available.
 408    *
 409    * @param methName The local name of the function.
 410    *
 411    * @return True if the function can be executed.
 412    */
 413   public boolean functionAvailable(String methName)
 414   {
 415       Integer tblEntry = m_functionID.get(methName);
 416       if (null != tblEntry) return true;
 417       else{
 418               tblEntry = m_functionID_customer.get(methName);
 419               return (null != tblEntry);
 420       }
 421   }
 422 }