1 /*
2  * Copyright (c) 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  "License");
10  * you may not use this file except in compliance with the License.
11  * 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.xml.internal.serializer.dom3;
23 
24 import java.util.Enumeration;
25 import java.util.NoSuchElementException;
26 
27 /**
28  * Namespace support for XML document handlers. This class doesn't
29  * perform any error checking and assumes that all strings passed
30  * as arguments to methods are unique symbols. The SymbolTable class
31  * can be used for this purpose.
32  *
33  * Derived from org.apache.xerces.util.NamespaceSupport
34  *
35  * @author Andy Clark, IBM
36  *
37  * @version $Id: Exp $
38  * @LastModified: Oct 2017
39  */
40 public class NamespaceSupport {
41 
42     static final String PREFIX_XML = "xml".intern();
43 
44     static final String PREFIX_XMLNS = "xmlns".intern();
45 
46     /**
47      * The XML Namespace ("http://www.w3.org/XML/1998/namespace"). This is
48      * the Namespace URI that is automatically mapped to the "xml" prefix.
49      */
50     public final static String XML_URI = "http://www.w3.org/XML/1998/namespace".intern();
51 
52     /**
53      * XML Information Set REC
54      * all namespace attributes (including those named xmlns,
55      * whose [prefix] property has no value) have a namespace URI of http://www.w3.org/2000/xmlns/
56      */
57     public final static String XMLNS_URI = "http://www.w3.org/2000/xmlns/".intern();
58 
59         //
60     // Data
61     //
62 
63     /**
64      * Namespace binding information. This array is composed of a
65      * series of tuples containing the namespace binding information:
66      * <prefix, uri>. The default size can be set to anything
67      * as long as it is a power of 2 greater than 1.
68      *
69      * @see #fNamespaceSize
70      * @see #fContext
71      */
72     protected String[] fNamespace = new String[16 * 2];
73 
74     /** The top of the namespace information array. */
75     protected int fNamespaceSize;
76 
77     // NOTE: The constructor depends on the initial context size
78     //       being at least 1. -Ac
79 
80     /**
81      * Context indexes. This array contains indexes into the namespace
82      * information array. The index at the current context is the start
83      * index of declared namespace bindings and runs to the size of the
84      * namespace information array.
85      *
86      * @see #fNamespaceSize
87      */
88     protected int[] fContext = new int[8];
89 
90     /** The current context. */
91     protected int fCurrentContext;
92 
93     protected String[] fPrefixes = new String[16];
94 
95     //
96     // Constructors
97     //
98 
99     /** Default constructor. */
NamespaceSupport()100     public NamespaceSupport() {
101     } // <init>()
102 
103     //
104     // Public methods
105     //
106 
107         /**
108          * @see org.apache.xerces.xni.NamespaceContext#reset()
109          */
reset()110     public void reset() {
111 
112         // reset namespace and context info
113         fNamespaceSize = 0;
114         fCurrentContext = 0;
115         fContext[fCurrentContext] = fNamespaceSize;
116 
117         // bind "xml" prefix to the XML uri
118         fNamespace[fNamespaceSize++] = PREFIX_XML;
119         fNamespace[fNamespaceSize++] = XML_URI;
120         // bind "xmlns" prefix to the XMLNS uri
121         fNamespace[fNamespaceSize++] = PREFIX_XMLNS;
122         fNamespace[fNamespaceSize++] = XMLNS_URI;
123         ++fCurrentContext;
124 
125     } // reset(SymbolTable)
126 
127 
128         /**
129          * @see org.apache.xerces.xni.NamespaceContext#pushContext()
130          */
pushContext()131     public void pushContext() {
132 
133         // extend the array, if necessary
134         if (fCurrentContext + 1 == fContext.length) {
135             int[] contextarray = new int[fContext.length * 2];
136             System.arraycopy(fContext, 0, contextarray, 0, fContext.length);
137             fContext = contextarray;
138         }
139 
140         // push context
141         fContext[++fCurrentContext] = fNamespaceSize;
142 
143     } // pushContext()
144 
145 
146         /**
147          * @see org.apache.xerces.xni.NamespaceContext#popContext()
148          */
popContext()149     public void popContext() {
150         fNamespaceSize = fContext[fCurrentContext--];
151     } // popContext()
152 
153         /**
154          * @see org.apache.xerces.xni.NamespaceContext#declarePrefix(String, String)
155          */
declarePrefix(String prefix, String uri)156     public boolean declarePrefix(String prefix, String uri) {
157         // ignore "xml" and "xmlns" prefixes
158         if (prefix == PREFIX_XML || prefix == PREFIX_XMLNS) {
159             return false;
160         }
161 
162         // see if prefix already exists in current context
163         for (int i = fNamespaceSize; i > fContext[fCurrentContext]; i -= 2) {
164             //if (fNamespace[i - 2] == prefix) {
165                 if (fNamespace[i - 2].equals(prefix) )  {
166                 // REVISIT: [Q] Should the new binding override the
167                 //          previously declared binding or should it
168                 //          it be ignored? -Ac
169                 // NOTE:    The SAX2 "NamespaceSupport" helper allows
170                 //          re-bindings with the new binding overwriting
171                 //          the previous binding. -Ac
172                 fNamespace[i - 1] = uri;
173                 return true;
174             }
175         }
176 
177         // resize array, if needed
178         if (fNamespaceSize == fNamespace.length) {
179             String[] namespacearray = new String[fNamespaceSize * 2];
180             System.arraycopy(fNamespace, 0, namespacearray, 0, fNamespaceSize);
181             fNamespace = namespacearray;
182         }
183 
184         // bind prefix to uri in current context
185         fNamespace[fNamespaceSize++] = prefix;
186         fNamespace[fNamespaceSize++] = uri;
187 
188         return true;
189 
190     } // declarePrefix(String,String):boolean
191 
192         /**
193          * @see org.apache.xerces.xni.NamespaceContext#getURI(String)
194          */
getURI(String prefix)195     public String getURI(String prefix) {
196 
197         // find prefix in current context
198         for (int i = fNamespaceSize; i > 0; i -= 2) {
199             //if (fNamespace[i - 2] == prefix) {
200                 if (fNamespace[i - 2].equals(prefix) ) {
201                 return fNamespace[i - 1];
202             }
203         }
204 
205         // prefix not found
206         return null;
207 
208     } // getURI(String):String
209 
210 
211         /**
212          * @see org.apache.xerces.xni.NamespaceContext#getPrefix(String)
213          */
getPrefix(String uri)214     public String getPrefix(String uri) {
215 
216         // find uri in current context
217         for (int i = fNamespaceSize; i > 0; i -= 2) {
218             //if (fNamespace[i - 1] == uri) {
219                 if (fNamespace[i - 1].equals(uri) ) {
220                 //if (getURI(fNamespace[i - 2]) == uri)
221                         if (getURI(fNamespace[i - 2]).equals(uri) )
222                     return fNamespace[i - 2];
223             }
224         }
225 
226         // uri not found
227         return null;
228 
229     } // getPrefix(String):String
230 
231 
232         /**
233          * @see org.apache.xerces.xni.NamespaceContext#getDeclaredPrefixCount()
234          */
getDeclaredPrefixCount()235     public int getDeclaredPrefixCount() {
236         return (fNamespaceSize - fContext[fCurrentContext]) / 2;
237     } // getDeclaredPrefixCount():int
238 
239         /**
240          * @see org.apache.xerces.xni.NamespaceContext#getDeclaredPrefixAt(int)
241          */
getDeclaredPrefixAt(int index)242     public String getDeclaredPrefixAt(int index) {
243         return fNamespace[fContext[fCurrentContext] + index * 2];
244     } // getDeclaredPrefixAt(int):String
245 
246         /**
247          * @see org.apache.xerces.xni.NamespaceContext#getAllPrefixes()
248          */
getAllPrefixes()249         public Enumeration<String> getAllPrefixes() {
250             int count = 0;
251             if (fPrefixes.length < (fNamespace.length/2)) {
252                 // resize prefix array
253                 String[] prefixes = new String[fNamespaceSize];
254                 fPrefixes = prefixes;
255             }
256             String prefix = null;
257             boolean unique = true;
258             for (int i = 2; i < (fNamespaceSize-2); i += 2) {
259                 prefix = fNamespace[i + 2];
260                 for (int k=0;k<count;k++){
261                     if (fPrefixes[k]==prefix){
262                         unique = false;
263                         break;
264                     }
265                 }
266                 if (unique){
267                     fPrefixes[count++] = prefix;
268                 }
269                 unique = true;
270             }
271             return new Prefixes(fPrefixes, count);
272         }
273 
274     protected final class Prefixes implements Enumeration<String> {
275         private String[] prefixes;
276         private int counter = 0;
277         private int size = 0;
278 
279                 /**
280                  * Constructor for Prefixes.
281                  */
Prefixes(String [] prefixes, int size)282                 public Prefixes(String [] prefixes, int size) {
283                         this.prefixes = prefixes;
284             this.size = size;
285                 }
286 
287        /**
288                  * @see java.util.Enumeration#hasMoreElements()
289                  */
hasMoreElements()290                 public boolean hasMoreElements() {
291                         return (counter< size);
292                 }
293 
294                 /**
295                  * @see java.util.Enumeration#nextElement()
296                  */
nextElement()297                 public String nextElement() {
298                     if (counter< size){
299                         return fPrefixes[counter++];
300                     }
301                     throw new NoSuchElementException("Illegal access to Namespace prefixes enumeration.");
302                 }
303 
toString()304         public String toString(){
305             StringBuilder buf = new StringBuilder();
306             for (int i=0;i<size;i++){
307                 buf.append(prefixes[i]);
308                 buf.append(" ");
309             }
310 
311             return buf.toString();
312         }
313 
314 }
315 
316 } // class NamespaceSupport
317