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. */
 100     public NamespaceSupport() {
 101     } // <init>()
 102 
 103     //
 104     // Public methods
 105     //
 106 
 107         /**
 108          * @see org.apache.xerces.xni.NamespaceContext#reset()
 109          */
 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          */
 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          */
 149     public void popContext() {
 150         fNamespaceSize = fContext[fCurrentContext--];
 151     } // popContext()
 152 
 153         /**
 154          * @see org.apache.xerces.xni.NamespaceContext#declarePrefix(String, String)
 155          */
 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          */
 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          */
 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          */
 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          */
 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          */
 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                  */
 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                  */
 290                 public boolean hasMoreElements() {
 291                         return (counter< size);
 292                 }
 293 
 294                 /**
 295                  * @see java.util.Enumeration#nextElement()
 296                  */
 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 
 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