1 /*
   2  * Copyright (c) 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 or more
   7  * contributor license agreements.  See the NOTICE file distributed with
   8  * this work for additional information regarding copyright ownership.
   9  * The ASF licenses this file to You under the Apache License, Version 2.0
  10  * (the "License"); you may not use this file except in compliance with
  11  * 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, software
  16  * distributed under the License is distributed on an "AS IS" BASIS,
  17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18  * See the License for the specific language governing permissions and
  19  * limitations under the License.
  20  */
  21 
  22 package com.sun.org.apache.xerces.internal.xinclude;
  23 
  24 import com.sun.org.apache.xerces.internal.util.NamespaceSupport;
  25 import com.sun.org.apache.xerces.internal.util.XMLSymbols;
  26 import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
  27 import java.util.Enumeration;
  28 
  29 /**
  30  * This implementation of NamespaceContext has the ability to maintain multiple
  31  * scopes of namespace/prefix bindings.  This is useful in situations when it is
  32  * not always appropriate for elements to inherit the namespace bindings of their
  33  * ancestors (such as included elements in XInclude).
  34  *
  35  * When searching for a URI to match a prefix, or a prefix to match a URI, it is
  36  * searched for in the current context, then the ancestors of the current context,
  37  * up to the beginning of the current scope.  Other scopes are not searched.
  38  *
  39  * @author Peter McCracken, IBM
  40  *
  41  */
  42 public class MultipleScopeNamespaceSupport extends NamespaceSupport {
  43 
  44     protected int[] fScope = new int[8];
  45     protected int fCurrentScope;
  46 
  47     /**
  48      *
  49      */
  50     public MultipleScopeNamespaceSupport() {
  51         super();
  52         fCurrentScope = 0;
  53         fScope[0] = 0;
  54     }
  55 
  56     /**
  57      * @param context
  58      */
  59     public MultipleScopeNamespaceSupport(NamespaceContext context) {
  60         super(context);
  61         fCurrentScope = 0;
  62         fScope[0] = 0;
  63     }
  64 
  65     /* (non-Javadoc)
  66      * @see com.sun.org.apache.xerces.internal.xni.NamespaceContext#getAllPrefixes()
  67      */
  68     public Enumeration<String> getAllPrefixes() {
  69         int count = 0;
  70         if (fPrefixes.length < (fNamespace.length / 2)) {
  71             // resize prefix array
  72             String[] prefixes = new String[fNamespaceSize];
  73             fPrefixes = prefixes;
  74         }
  75         String prefix = null;
  76         boolean unique = true;
  77         for (int i = fContext[fScope[fCurrentScope]];
  78             i <= (fNamespaceSize - 2);
  79             i += 2) {
  80             prefix = fNamespace[i];
  81             for (int k = 0; k < count; k++) {
  82                 if (fPrefixes[k] == prefix) {
  83                     unique = false;
  84                     break;
  85                 }
  86             }
  87             if (unique) {
  88                 fPrefixes[count++] = prefix;
  89             }
  90             unique = true;
  91         }
  92         return new Prefixes(fPrefixes, count);
  93     }
  94 
  95     public int getScopeForContext(int context) {
  96         int scope = fCurrentScope;
  97         while (context < fScope[scope]) {
  98             scope--;
  99         }
 100         return scope;
 101     }
 102 
 103     /* (non-Javadoc)
 104      * @see com.sun.org.apache.xerces.internal.xni.NamespaceContext#getPrefix(java.lang.String)
 105      */
 106     public String getPrefix(String uri) {
 107         return getPrefix(uri, fNamespaceSize, fContext[fScope[fCurrentScope]]);
 108     }
 109 
 110     /* (non-Javadoc)
 111      * @see com.sun.org.apache.xerces.internal.xni.NamespaceContext#getURI(java.lang.String)
 112      */
 113     public String getURI(String prefix) {
 114         return getURI(prefix, fNamespaceSize, fContext[fScope[fCurrentScope]]);
 115     }
 116 
 117     public String getPrefix(String uri, int context) {
 118         return getPrefix(uri, fContext[context+1], fContext[fScope[getScopeForContext(context)]]);
 119     }
 120 
 121     public String getURI(String prefix, int context) {
 122         return getURI(prefix, fContext[context+1], fContext[fScope[getScopeForContext(context)]]);
 123     }
 124 
 125     public String getPrefix(String uri, int start, int end) {
 126         // this saves us from having a copy of each of these in fNamespace for each scope
 127         if (uri == NamespaceContext.XML_URI) {
 128             return XMLSymbols.PREFIX_XML;
 129         }
 130         if (uri == NamespaceContext.XMLNS_URI) {
 131             return XMLSymbols.PREFIX_XMLNS;
 132         }
 133 
 134         // find uri in current context
 135         for (int i = start; i > end; i -= 2) {
 136             if (fNamespace[i - 1] == uri) {
 137                 if (getURI(fNamespace[i - 2]) == uri)
 138                     return fNamespace[i - 2];
 139             }
 140         }
 141 
 142         // uri not found
 143         return null;
 144     }
 145 
 146     public String getURI(String prefix, int start, int end) {
 147         // this saves us from having a copy of each of these in fNamespace for each scope
 148         if (prefix == XMLSymbols.PREFIX_XML) {
 149             return NamespaceContext.XML_URI;
 150         }
 151         if (prefix == XMLSymbols.PREFIX_XMLNS) {
 152             return NamespaceContext.XMLNS_URI;
 153         }
 154 
 155         // find prefix in current context
 156         for (int i = start; i > end; i -= 2) {
 157             if (fNamespace[i - 2] == prefix) {
 158                 return fNamespace[i - 1];
 159             }
 160         }
 161 
 162         // prefix not found
 163         return null;
 164     }
 165 
 166     /**
 167      * Only resets the current scope -- all namespaces defined in lower scopes
 168      * remain valid after a call to reset.
 169      */
 170     public void reset() {
 171         fCurrentContext = fScope[fCurrentScope];
 172         fNamespaceSize = fContext[fCurrentContext];
 173     }
 174 
 175     /**
 176      * Begins a new scope.  None of the previous namespace bindings will be used,
 177      * until the new scope is popped with popScope()
 178      */
 179     public void pushScope() {
 180         if (fCurrentScope + 1 == fScope.length) {
 181             int[] contextarray = new int[fScope.length * 2];
 182             System.arraycopy(fScope, 0, contextarray, 0, fScope.length);
 183             fScope = contextarray;
 184         }
 185         pushContext();
 186         fScope[++fCurrentScope] = fCurrentContext;
 187     }
 188 
 189     /**
 190      * Pops the current scope.  The namespace bindings from the new current scope
 191      * are then used for searching for namespaces and prefixes.
 192      */
 193     public void popScope() {
 194         fCurrentContext = fScope[fCurrentScope--];
 195         popContext();
 196     }
 197 }