1 /*
   2  * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package org.xml.sax.helpers;
  27 
  28 import java.util.ArrayList;
  29 import java.util.Collections;
  30 import java.util.EmptyStackException;
  31 import java.util.Enumeration;
  32 import java.util.HashMap;
  33 import java.util.List;
  34 import java.util.Map;
  35 
  36 
  37 /**
  38  * Encapsulate Namespace logic for use by applications using SAX,
  39  * or internally by SAX drivers.
  40  *
  41  * <p>This class encapsulates the logic of Namespace processing: it
  42  * tracks the declarations currently in force for each context and
  43  * automatically processes qualified XML names into their Namespace
  44  * parts; it can also be used in reverse for generating XML qnames
  45  * from Namespaces.</p>
  46  *
  47  * <p>Namespace support objects are reusable, but the reset method
  48  * must be invoked between each session.</p>
  49  *
  50  * <p>Here is a simple session:</p>
  51  *
  52  * <pre>
  53  * String parts[] = new String[3];
  54  * NamespaceSupport support = new NamespaceSupport();
  55  *
  56  * support.pushContext();
  57  * support.declarePrefix("", "http://www.w3.org/1999/xhtml");
  58  * support.declarePrefix("dc", "http://www.purl.org/dc#");
  59  *
  60  * parts = support.processName("p", parts, false);
  61  * System.out.println("Namespace URI: " + parts[0]);
  62  * System.out.println("Local name: " + parts[1]);
  63  * System.out.println("Raw name: " + parts[2]);
  64  *
  65  * parts = support.processName("dc:title", parts, false);
  66  * System.out.println("Namespace URI: " + parts[0]);
  67  * System.out.println("Local name: " + parts[1]);
  68  * System.out.println("Raw name: " + parts[2]);
  69  *
  70  * support.popContext();
  71  * </pre>
  72  *
  73  * <p>Note that this class is optimized for the use case where most
  74  * elements do not contain Namespace declarations: if the same
  75  * prefix/URI mapping is repeated for each context (for example), this
  76  * class will be somewhat less efficient.</p>
  77  *
  78  * <p>Although SAX drivers (parsers) may choose to use this class to
  79  * implement namespace handling, they are not required to do so.
  80  * Applications must track namespace information themselves if they
  81  * want to use namespace information.
  82  *
  83  * @since 1.4, SAX 2.0
  84  * @author David Megginson
  85  */
  86 public class NamespaceSupport
  87 {
  88 
  89 
  90     ////////////////////////////////////////////////////////////////////
  91     // Constants.
  92     ////////////////////////////////////////////////////////////////////
  93 
  94 
  95     /**
  96      * The XML Namespace URI as a constant.
  97      * The value is <code>http://www.w3.org/XML/1998/namespace</code>
  98      * as defined in the "Namespaces in XML" * recommendation.
  99      *
 100      * <p>This is the Namespace URI that is automatically mapped
 101      * to the "xml" prefix.</p>
 102      */
 103     public final static String XMLNS =
 104         "http://www.w3.org/XML/1998/namespace";
 105 
 106 
 107     /**
 108      * The namespace declaration URI as a constant.
 109      * The value is <code>http://www.w3.org/xmlns/2000/</code>, as defined
 110      * in a backwards-incompatible erratum to the "Namespaces in XML"
 111      * recommendation.  Because that erratum postdated SAX2, SAX2 defaults
 112      * to the original recommendation, and does not normally use this URI.
 113      *
 114      *
 115      * <p>This is the Namespace URI that is optionally applied to
 116      * <em>xmlns</em> and <em>xmlns:*</em> attributes, which are used to
 117      * declare namespaces.  </p>
 118      *
 119      * @since 1.5, SAX 2.1alpha
 120      * @see #setNamespaceDeclUris
 121      * @see #isNamespaceDeclUris
 122      */
 123     public final static String NSDECL =
 124         "http://www.w3.org/xmlns/2000/";
 125 
 126 
 127     /**
 128      * An empty enumeration.
 129      */
 130     private final static Enumeration<String> EMPTY_ENUMERATION =
 131             Collections.enumeration(new ArrayList<String>());
 132 
 133 
 134     ////////////////////////////////////////////////////////////////////
 135     // Constructor.
 136     ////////////////////////////////////////////////////////////////////
 137 
 138 
 139     /**
 140      * Create a new Namespace support object.
 141      */
 142     public NamespaceSupport ()
 143     {
 144         reset();
 145     }
 146 
 147 
 148 
 149     ////////////////////////////////////////////////////////////////////
 150     // Context management.
 151     ////////////////////////////////////////////////////////////////////
 152 
 153 
 154     /**
 155      * Reset this Namespace support object for reuse.
 156      *
 157      * <p>It is necessary to invoke this method before reusing the
 158      * Namespace support object for a new session.  If namespace
 159      * declaration URIs are to be supported, that flag must also
 160      * be set to a non-default value.
 161      * </p>
 162      *
 163      * @see #setNamespaceDeclUris
 164      */
 165     public void reset ()
 166     {
 167         contexts = new Context[32];
 168         namespaceDeclUris = false;
 169         contextPos = 0;
 170         contexts[contextPos] = currentContext = new Context();
 171         currentContext.declarePrefix("xml", XMLNS);
 172     }
 173 
 174 
 175     /**
 176      * Start a new Namespace context.
 177      * The new context will automatically inherit
 178      * the declarations of its parent context, but it will also keep
 179      * track of which declarations were made within this context.
 180      *
 181      * <p>Event callback code should start a new context once per element.
 182      * This means being ready to call this in either of two places.
 183      * For elements that don't include namespace declarations, the
 184      * <em>ContentHandler.startElement()</em> callback is the right place.
 185      * For elements with such a declaration, it'd done in the first
 186      * <em>ContentHandler.startPrefixMapping()</em> callback.
 187      * A boolean flag can be used to
 188      * track whether a context has been started yet.  When either of
 189      * those methods is called, it checks the flag to see if a new context
 190      * needs to be started.  If so, it starts the context and sets the
 191      * flag.  After <em>ContentHandler.startElement()</em>
 192      * does that, it always clears the flag.
 193      *
 194      * <p>Normally, SAX drivers would push a new context at the beginning
 195      * of each XML element.  Then they perform a first pass over the
 196      * attributes to process all namespace declarations, making
 197      * <em>ContentHandler.startPrefixMapping()</em> callbacks.
 198      * Then a second pass is made, to determine the namespace-qualified
 199      * names for all attributes and for the element name.
 200      * Finally all the information for the
 201      * <em>ContentHandler.startElement()</em> callback is available,
 202      * so it can then be made.
 203      *
 204      * <p>The Namespace support object always starts with a base context
 205      * already in force: in this context, only the "xml" prefix is
 206      * declared.</p>
 207      *
 208      * @see org.xml.sax.ContentHandler
 209      * @see #popContext
 210      */
 211     public void pushContext ()
 212     {
 213         int max = contexts.length;
 214 
 215         contextPos++;
 216 
 217                                 // Extend the array if necessary
 218         if (contextPos >= max) {
 219             Context newContexts[] = new Context[max*2];
 220             System.arraycopy(contexts, 0, newContexts, 0, max);
 221             max *= 2;
 222             contexts = newContexts;
 223         }
 224 
 225                                 // Allocate the context if necessary.
 226         currentContext = contexts[contextPos];
 227         if (currentContext == null) {
 228             contexts[contextPos] = currentContext = new Context();
 229         }
 230 
 231                                 // Set the parent, if any.
 232         if (contextPos > 0) {
 233             currentContext.setParent(contexts[contextPos - 1]);
 234         }
 235     }
 236 
 237 
 238     /**
 239      * Revert to the previous Namespace context.
 240      *
 241      * <p>Normally, you should pop the context at the end of each
 242      * XML element.  After popping the context, all Namespace prefix
 243      * mappings that were previously in force are restored.</p>
 244      *
 245      * <p>You must not attempt to declare additional Namespace
 246      * prefixes after popping a context, unless you push another
 247      * context first.</p>
 248      *
 249      * @see #pushContext
 250      */
 251     public void popContext ()
 252     {
 253         contexts[contextPos].clear();
 254         contextPos--;
 255         if (contextPos < 0) {
 256             throw new EmptyStackException();
 257         }
 258         currentContext = contexts[contextPos];
 259     }
 260 
 261 
 262 
 263     ////////////////////////////////////////////////////////////////////
 264     // Operations within a context.
 265     ////////////////////////////////////////////////////////////////////
 266 
 267 
 268     /**
 269      * Declare a Namespace prefix.  All prefixes must be declared
 270      * before they are referenced.  For example, a SAX driver (parser)
 271      * would scan an element's attributes
 272      * in two passes:  first for namespace declarations,
 273      * then a second pass using {@link #processName processName()} to
 274      * interpret prefixes against (potentially redefined) prefixes.
 275      *
 276      * <p>This method declares a prefix in the current Namespace
 277      * context; the prefix will remain in force until this context
 278      * is popped, unless it is shadowed in a descendant context.</p>
 279      *
 280      * <p>To declare the default element Namespace, use the empty string as
 281      * the prefix.</p>
 282      *
 283      * <p>Note that there is an asymmetry in this library: {@link
 284      * #getPrefix getPrefix} will not return the "" prefix,
 285      * even if you have declared a default element namespace.
 286      * To check for a default namespace,
 287      * you have to look it up explicitly using {@link #getURI getURI}.
 288      * This asymmetry exists to make it easier to look up prefixes
 289      * for attribute names, where the default prefix is not allowed.</p>
 290      *
 291      * @param prefix The prefix to declare, or the empty string to
 292      *  indicate the default element namespace.  This may never have
 293      *  the value "xml" or "xmlns".
 294      * @param uri The Namespace URI to associate with the prefix.
 295      * @return true if the prefix was legal, false otherwise
 296      *
 297      * @see #processName
 298      * @see #getURI
 299      * @see #getPrefix
 300      */
 301     public boolean declarePrefix (String prefix, String uri)
 302     {
 303         if (prefix.equals("xml") || prefix.equals("xmlns")) {
 304             return false;
 305         } else {
 306             currentContext.declarePrefix(prefix, uri);
 307             return true;
 308         }
 309     }
 310 
 311 
 312     /**
 313      * Process a raw XML qualified name, after all declarations in the
 314      * current context have been handled by {@link #declarePrefix
 315      * declarePrefix()}.
 316      *
 317      * <p>This method processes a raw XML qualified name in the
 318      * current context by removing the prefix and looking it up among
 319      * the prefixes currently declared.  The return value will be the
 320      * array supplied by the caller, filled in as follows:</p>
 321      *
 322      * <dl>
 323      * <dt>parts[0]</dt>
 324      * <dd>The Namespace URI, or an empty string if none is
 325      *  in use.</dd>
 326      * <dt>parts[1]</dt>
 327      * <dd>The local name (without prefix).</dd>
 328      * <dt>parts[2]</dt>
 329      * <dd>The original raw name.</dd>
 330      * </dl>
 331      *
 332      * <p>All of the strings in the array will be internalized.  If
 333      * the raw name has a prefix that has not been declared, then
 334      * the return value will be null.</p>
 335      *
 336      * <p>Note that attribute names are processed differently than
 337      * element names: an unprefixed element name will receive the
 338      * default Namespace (if any), while an unprefixed attribute name
 339      * will not.</p>
 340      *
 341      * @param qName The XML qualified name to be processed.
 342      * @param parts An array supplied by the caller, capable of
 343      *        holding at least three members.
 344      * @param isAttribute A flag indicating whether this is an
 345      *        attribute name (true) or an element name (false).
 346      * @return The supplied array holding three internalized strings
 347      *        representing the Namespace URI (or empty string), the
 348      *        local name, and the XML qualified name; or null if there
 349      *        is an undeclared prefix.
 350      * @see #declarePrefix
 351      * @see java.lang.String#intern */
 352     public String [] processName (String qName, String parts[],
 353                                   boolean isAttribute)
 354     {
 355         String myParts[] = currentContext.processName(qName, isAttribute);
 356         if (myParts == null) {
 357             return null;
 358         } else {
 359             parts[0] = myParts[0];
 360             parts[1] = myParts[1];
 361             parts[2] = myParts[2];
 362             return parts;
 363         }
 364     }
 365 
 366 
 367     /**
 368      * Look up a prefix and get the currently-mapped Namespace URI.
 369      *
 370      * <p>This method looks up the prefix in the current context.
 371      * Use the empty string ("") for the default Namespace.</p>
 372      *
 373      * @param prefix The prefix to look up.
 374      * @return The associated Namespace URI, or null if the prefix
 375      *         is undeclared in this context.
 376      * @see #getPrefix
 377      * @see #getPrefixes
 378      */
 379     public String getURI (String prefix)
 380     {
 381         return currentContext.getURI(prefix);
 382     }
 383 
 384 
 385     /**
 386      * Return an enumeration of all prefixes whose declarations are
 387      * active in the current context.
 388      * This includes declarations from parent contexts that have
 389      * not been overridden.
 390      *
 391      * <p><strong>Note:</strong> if there is a default prefix, it will not be
 392      * returned in this enumeration; check for the default prefix
 393      * using the {@link #getURI getURI} with an argument of "".</p>
 394      *
 395      * @return An enumeration of prefixes (never empty).
 396      * @see #getDeclaredPrefixes
 397      * @see #getURI
 398      */
 399     public Enumeration<String> getPrefixes ()
 400     {
 401         return currentContext.getPrefixes();
 402     }
 403 
 404 
 405     /**
 406      * Return one of the prefixes mapped to a Namespace URI.
 407      *
 408      * <p>If more than one prefix is currently mapped to the same
 409      * URI, this method will make an arbitrary selection; if you
 410      * want all of the prefixes, use the {@link #getPrefixes}
 411      * method instead.</p>
 412      *
 413      * <p><strong>Note:</strong> this will never return the empty (default) prefix;
 414      * to check for a default prefix, use the {@link #getURI getURI}
 415      * method with an argument of "".</p>
 416      *
 417      * @param uri the namespace URI
 418      * @return one of the prefixes currently mapped to the URI supplied,
 419      *         or null if none is mapped or if the URI is assigned to
 420      *         the default namespace
 421      * @see #getPrefixes(java.lang.String)
 422      * @see #getURI
 423      */
 424     public String getPrefix (String uri)
 425     {
 426         return currentContext.getPrefix(uri);
 427     }
 428 
 429 
 430     /**
 431      * Return an enumeration of all prefixes for a given URI whose
 432      * declarations are active in the current context.
 433      * This includes declarations from parent contexts that have
 434      * not been overridden.
 435      *
 436      * <p>This method returns prefixes mapped to a specific Namespace
 437      * URI.  The xml: prefix will be included.  If you want only one
 438      * prefix that's mapped to the Namespace URI, and you don't care
 439      * which one you get, use the {@link #getPrefix getPrefix}
 440      *  method instead.</p>
 441      *
 442      * <p><strong>Note:</strong> the empty (default) prefix is <em>never</em> included
 443      * in this enumeration; to check for the presence of a default
 444      * Namespace, use the {@link #getURI getURI} method with an
 445      * argument of "".</p>
 446      *
 447      * @param uri The Namespace URI.
 448      * @return An enumeration of prefixes (never empty).
 449      * @see #getPrefix
 450      * @see #getDeclaredPrefixes
 451      * @see #getURI
 452      */
 453     public Enumeration<String> getPrefixes (String uri)
 454     {
 455         List<String> prefixes = new ArrayList<>();
 456         Enumeration<String> allPrefixes = getPrefixes();
 457         while (allPrefixes.hasMoreElements()) {
 458             String prefix = allPrefixes.nextElement();
 459             if (uri.equals(getURI(prefix))) {
 460                 prefixes.add(prefix);
 461             }
 462         }
 463         return Collections.enumeration(prefixes);
 464     }
 465 
 466 
 467     /**
 468      * Return an enumeration of all prefixes declared in this context.
 469      *
 470      * <p>The empty (default) prefix will be included in this
 471      * enumeration; note that this behaviour differs from that of
 472      * {@link #getPrefix} and {@link #getPrefixes}.</p>
 473      *
 474      * @return An enumeration of all prefixes declared in this
 475      *         context.
 476      * @see #getPrefixes
 477      * @see #getURI
 478      */
 479     public Enumeration<String> getDeclaredPrefixes ()
 480     {
 481         return currentContext.getDeclaredPrefixes();
 482     }
 483 
 484     /**
 485      * Controls whether namespace declaration attributes are placed
 486      * into the {@link #NSDECL NSDECL} namespace
 487      * by {@link #processName processName()}.  This may only be
 488      * changed before any contexts have been pushed.
 489      *
 490      * @param value a flag indicating whether namespace declaration attributes
 491      * are placed into the {@link #NSDECL NSDECL} namespace
 492      * @since 1.5, SAX 2.1alpha
 493      *
 494      * @exception IllegalStateException when attempting to set this
 495      *  after any context has been pushed.
 496      */
 497     public void setNamespaceDeclUris (boolean value)
 498     {
 499         if (contextPos != 0)
 500             throw new IllegalStateException ();
 501         if (value == namespaceDeclUris)
 502             return;
 503         namespaceDeclUris = value;
 504         if (value)
 505             currentContext.declarePrefix ("xmlns", NSDECL);
 506         else {
 507             contexts[contextPos] = currentContext = new Context();
 508             currentContext.declarePrefix("xml", XMLNS);
 509         }
 510     }
 511 
 512     /**
 513      * Returns true if namespace declaration attributes are placed into
 514      * a namespace.  This behavior is not the default.
 515      *
 516      * @return true if namespace declaration attributes are placed into a namespace,
 517      * false otherwise
 518      * @since 1.5, SAX 2.1alpha
 519      */
 520     public boolean isNamespaceDeclUris ()
 521         { return namespaceDeclUris; }
 522 
 523 
 524 
 525     ////////////////////////////////////////////////////////////////////
 526     // Internal state.
 527     ////////////////////////////////////////////////////////////////////
 528 
 529     private Context contexts[];
 530     private Context currentContext;
 531     private int contextPos;
 532     private boolean namespaceDeclUris;
 533 
 534 
 535     ////////////////////////////////////////////////////////////////////
 536     // Internal classes.
 537     ////////////////////////////////////////////////////////////////////
 538 
 539     /**
 540      * Internal class for a single Namespace context.
 541      *
 542      * <p>This module caches and reuses Namespace contexts,
 543      * so the number allocated
 544      * will be equal to the element depth of the document, not to the total
 545      * number of elements (i.e. 5-10 rather than tens of thousands).
 546      * Also, data structures used to represent contexts are shared when
 547      * possible (child contexts without declarations) to further reduce
 548      * the amount of memory that's consumed.
 549      * </p>
 550      */
 551     final class Context {
 552 
 553         /**
 554          * Create the root-level Namespace context.
 555          */
 556         Context ()
 557         {
 558             copyTables();
 559         }
 560 
 561 
 562         /**
 563          * (Re)set the parent of this Namespace context.
 564          * The context must either have been freshly constructed,
 565          * or must have been cleared.
 566          *
 567          * @param context The parent Namespace context object.
 568          */
 569         void setParent (Context parent)
 570         {
 571             this.parent = parent;
 572             declarations = null;
 573             prefixTable = parent.prefixTable;
 574             uriTable = parent.uriTable;
 575             elementNameTable = parent.elementNameTable;
 576             attributeNameTable = parent.attributeNameTable;
 577             defaultNS = parent.defaultNS;
 578             declSeen = false;
 579         }
 580 
 581         /**
 582          * Makes associated state become collectible,
 583          * invalidating this context.
 584          * {@link #setParent} must be called before
 585          * this context may be used again.
 586          */
 587         void clear ()
 588         {
 589             parent = null;
 590             prefixTable = null;
 591             uriTable = null;
 592             elementNameTable = null;
 593             attributeNameTable = null;
 594             defaultNS = null;
 595         }
 596 
 597 
 598         /**
 599          * Declare a Namespace prefix for this context.
 600          *
 601          * @param prefix The prefix to declare.
 602          * @param uri The associated Namespace URI.
 603          * @see org.xml.sax.helpers.NamespaceSupport#declarePrefix
 604          */
 605         void declarePrefix (String prefix, String uri)
 606         {
 607                                 // Lazy processing...
 608 //          if (!declsOK)
 609 //              throw new IllegalStateException (
 610 //                  "can't declare any more prefixes in this context");
 611             if (!declSeen) {
 612                 copyTables();
 613             }
 614             if (declarations == null) {
 615                 declarations = new ArrayList<>();
 616             }
 617 
 618             prefix = prefix.intern();
 619             uri = uri.intern();
 620             if ("".equals(prefix)) {
 621                 if ("".equals(uri)) {
 622                     defaultNS = null;
 623                 } else {
 624                     defaultNS = uri;
 625                 }
 626             } else {
 627                 prefixTable.put(prefix, uri);
 628                 uriTable.put(uri, prefix); // may wipe out another prefix
 629             }
 630             declarations.add(prefix);
 631         }
 632 
 633 
 634         /**
 635          * Process an XML qualified name in this context.
 636          *
 637          * @param qName The XML qualified name.
 638          * @param isAttribute true if this is an attribute name.
 639          * @return An array of three strings containing the
 640          *         URI part (or empty string), the local part,
 641          *         and the raw name, all internalized, or null
 642          *         if there is an undeclared prefix.
 643          * @see org.xml.sax.helpers.NamespaceSupport#processName
 644          */
 645         String [] processName (String qName, boolean isAttribute)
 646         {
 647             String name[];
 648             Map<String, String[]> table;
 649 
 650             // Select the appropriate table.
 651             if (isAttribute) {
 652                 table = attributeNameTable;
 653             } else {
 654                 table = elementNameTable;
 655             }
 656 
 657             // Start by looking in the cache, and
 658             // return immediately if the name
 659             // is already known in this content
 660             name = table.get(qName);
 661             if (name != null) {
 662                 return name;
 663             }
 664 
 665             // We haven't seen this name in this
 666             // context before.  Maybe in the parent
 667             // context, but we can't assume prefix
 668             // bindings are the same.
 669             name = new String[3];
 670             name[2] = qName.intern();
 671             int index = qName.indexOf(':');
 672 
 673 
 674             // No prefix.
 675             if (index == -1) {
 676                 if (isAttribute) {
 677                     if (qName == "xmlns" && namespaceDeclUris)
 678                         name[0] = NSDECL;
 679                     else
 680                         name[0] = "";
 681                 } else if (defaultNS == null) {
 682                     name[0] = "";
 683                 } else {
 684                     name[0] = defaultNS;
 685                 }
 686                 name[1] = name[2];
 687             }
 688 
 689             // Prefix
 690             else {
 691                 String prefix = qName.substring(0, index);
 692                 String local = qName.substring(index+1);
 693                 String uri;
 694                 if ("".equals(prefix)) {
 695                     uri = defaultNS;
 696                 } else {
 697                     uri = prefixTable.get(prefix);
 698                 }
 699                 if (uri == null
 700                         || (!isAttribute && "xmlns".equals (prefix))) {
 701                     return null;
 702                 }
 703                 name[0] = uri;
 704                 name[1] = local.intern();
 705             }
 706 
 707             // Save in the cache for future use.
 708             // (Could be shared with parent context...)
 709             table.put(name[2], name);
 710             return name;
 711         }
 712 
 713 
 714         /**
 715          * Look up the URI associated with a prefix in this context.
 716          *
 717          * @param prefix The prefix to look up.
 718          * @return The associated Namespace URI, or null if none is
 719          *         declared.
 720          * @see org.xml.sax.helpers.NamespaceSupport#getURI
 721          */
 722         String getURI (String prefix)
 723         {
 724             if ("".equals(prefix)) {
 725                 return defaultNS;
 726             } else if (prefixTable == null) {
 727                 return null;
 728             } else {
 729                 return prefixTable.get(prefix);
 730             }
 731         }
 732 
 733 
 734         /**
 735          * Look up one of the prefixes associated with a URI in this context.
 736          *
 737          * <p>Since many prefixes may be mapped to the same URI,
 738          * the return value may be unreliable.</p>
 739          *
 740          * @param uri The URI to look up.
 741          * @return The associated prefix, or null if none is declared.
 742          * @see org.xml.sax.helpers.NamespaceSupport#getPrefix
 743          */
 744         String getPrefix (String uri)
 745         {
 746             if (uriTable == null) {
 747                 return null;
 748             } else {
 749                 return uriTable.get(uri);
 750             }
 751         }
 752 
 753 
 754         /**
 755          * Return an enumeration of prefixes declared in this context.
 756          *
 757          * @return An enumeration of prefixes (possibly empty).
 758          * @see org.xml.sax.helpers.NamespaceSupport#getDeclaredPrefixes
 759          */
 760         Enumeration<String> getDeclaredPrefixes ()
 761         {
 762             if (declarations == null) {
 763                 return EMPTY_ENUMERATION;
 764             } else {
 765                 return Collections.enumeration(declarations);
 766             }
 767         }
 768 
 769         /**
 770          * Return an enumeration of all prefixes currently in force.
 771          *
 772          * <p>The default prefix, if in force, is <em>not</em>
 773          * returned, and will have to be checked for separately.</p>
 774          *
 775          * @return An enumeration of prefixes (never empty).
 776          * @see org.xml.sax.helpers.NamespaceSupport#getPrefixes
 777          */
 778         Enumeration<String> getPrefixes ()
 779         {
 780             if (prefixTable == null) {
 781                 return EMPTY_ENUMERATION;
 782             } else {
 783                 return Collections.enumeration(prefixTable.keySet());
 784             }
 785         }
 786 
 787 
 788 
 789         ////////////////////////////////////////////////////////////////
 790         // Internal methods.
 791         ////////////////////////////////////////////////////////////////
 792 
 793 
 794         /**
 795          * Copy on write for the internal tables in this context.
 796          *
 797          * <p>This class is optimized for the normal case where most
 798          * elements do not contain Namespace declarations.</p>
 799          */
 800         private void copyTables ()
 801         {
 802             if (prefixTable != null) {
 803                 prefixTable = new HashMap<>(prefixTable);
 804             } else {
 805                 prefixTable = new HashMap<>();
 806             }
 807             if (uriTable != null) {
 808                 uriTable = new HashMap<>(uriTable);
 809             } else {
 810                 uriTable = new HashMap<>();
 811             }
 812             elementNameTable = new HashMap<>();
 813             attributeNameTable = new HashMap<>();
 814             declSeen = true;
 815         }
 816 
 817 
 818 
 819         ////////////////////////////////////////////////////////////////
 820         // Protected state.
 821         ////////////////////////////////////////////////////////////////
 822 
 823         Map<String, String> prefixTable;
 824         Map<String, String> uriTable;
 825         Map<String, String[]> elementNameTable;
 826         Map<String, String[]> attributeNameTable;
 827         String defaultNS = null;
 828 
 829 
 830 
 831         ////////////////////////////////////////////////////////////////
 832         // Internal state.
 833         ////////////////////////////////////////////////////////////////
 834 
 835         private List<String> declarations = null;
 836         private boolean declSeen = false;
 837         private Context parent = null;
 838     }
 839 }
 840 
 841 // end of NamespaceSupport.java