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