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