1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 /*
   6  * The Apache Software License, Version 1.1
   7  *
   8  *
   9  * Copyright (c) 1999-2003 The Apache Software Foundation.
  10  * All rights reserved.
  11  *
  12  * Redistribution and use in source and binary forms, with or without
  13  * modification, are permitted provided that the following conditions
  14  * are met:
  15  *
  16  * 1. Redistributions of source code must retain the above copyright
  17  *    notice, this list of conditions and the following disclaimer.
  18  *
  19  * 2. Redistributions in binary form must reproduce the above copyright
  20  *    notice, this list of conditions and the following disclaimer in
  21  *    the documentation and/or other materials provided with the
  22  *    distribution.
  23  *
  24  * 3. The end-user documentation included with the redistribution,
  25  *    if any, must include the following acknowledgment:
  26  *       "This product includes software developed by the
  27  *        Apache Software Foundation (http://www.apache.org/)."
  28  *    Alternately, this acknowledgment may appear in the software itself,
  29  *    if and wherever such third-party acknowledgments normally appear.
  30  *
  31  * 4. The names "Xerces" and "Apache Software Foundation" must
  32  *    not be used to endorse or promote products derived from this
  33  *    software without prior written permission. For written
  34  *    permission, please contact apache@apache.org.
  35  *
  36  * 5. Products derived from this software may not be called "Apache",
  37  *    nor may "Apache" appear in their name, without prior written
  38  *    permission of the Apache Software Foundation.
  39  *
  40  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  41  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  42  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  43  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  44  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  45  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  46  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  47  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  48  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  49  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  50  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  51  * SUCH DAMAGE.
  52  * ====================================================================
  53  *
  54  * This software consists of voluntary contributions made by many
  55  * individuals on behalf of the Apache Software Foundation and was
  56  * originally based on software copyright (c) 2002, International
  57  * Business Machines, Inc., http://www.apache.org.  For more
  58  * information on the Apache Software Foundation, please see
  59  * <http://www.apache.org/>.
  60  */
  61 
  62 package com.sun.org.apache.xerces.internal.impl.dtd;
  63 
  64 import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter;
  65 import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
  66 import com.sun.org.apache.xerces.internal.util.XMLSymbols;
  67 import com.sun.org.apache.xerces.internal.xni.Augmentations;
  68 import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
  69 import com.sun.org.apache.xerces.internal.xni.QName;
  70 import com.sun.org.apache.xerces.internal.xni.XMLAttributes;
  71 import com.sun.org.apache.xerces.internal.xni.XNIException;
  72 
  73 /**
  74  * The DTD validator. The validator implements a document
  75  * filter: receiving document events from the scanner; validating
  76  * the content and structure; augmenting the InfoSet, if applicable;
  77  * and notifying the parser of the information resulting from the
  78  * validation process.
  79  * <p> Formerly, this component also handled DTD events and grammar construction.
  80  * To facilitate the development of a meaningful DTD grammar caching/preparsing
  81  * framework, this functionality has been moved into the XMLDTDLoader
  82  * class.  Therefore, this class no longer implements the DTDFilter
  83  * or DTDContentModelFilter interfaces.
  84  * <p>
  85  * This component requires the following features and properties from the
  86  * component manager that uses it:
  87  * <ul>
  88  *  <li>http://xml.org/sax/features/namespaces</li>
  89  *  <li>http://xml.org/sax/features/validation</li>
  90  *  <li>http://apache.org/xml/features/validation/dynamic</li>
  91  *  <li>http://apache.org/xml/properties/internal/symbol-table</li>
  92  *  <li>http://apache.org/xml/properties/internal/error-reporter</li>
  93  *  <li>http://apache.org/xml/properties/internal/grammar-pool</li>
  94  *  <li>http://apache.org/xml/properties/internal/datatype-validator-factory</li>
  95  * </ul>
  96  *
  97  * @xerces.internal
  98  *
  99  * @author Elena Litani, IBM
 100  * @author Michael Glavassevich, IBM
 101  *
 102 
 103  */
 104 public class XML11NSDTDValidator extends XML11DTDValidator {
 105 
 106     /** Attribute QName. */
 107     private QName fAttributeQName = new QName();
 108 
 109     /** Bind namespaces */
 110     protected final void startNamespaceScope(QName element, XMLAttributes attributes, Augmentations augs)
 111         throws XNIException {
 112 
 113         // add new namespace context
 114         fNamespaceContext.pushContext();
 115 
 116         if (element.prefix == XMLSymbols.PREFIX_XMLNS) {
 117             fErrorReporter.reportError(
 118                 XMLMessageFormatter.XMLNS_DOMAIN,
 119                 "ElementXMLNSPrefix",
 120                 new Object[] { element.rawname },
 121                 XMLErrorReporter.SEVERITY_FATAL_ERROR);
 122         }
 123 
 124         // search for new namespace bindings
 125         int length = attributes.getLength();
 126         for (int i = 0; i < length; i++) {
 127             String localpart = attributes.getLocalName(i);
 128             String prefix = attributes.getPrefix(i);
 129             // when it's of form xmlns="..." or xmlns:prefix="...",
 130             // it's a namespace declaration. but prefix:xmlns="..." isn't.
 131             if (prefix == XMLSymbols.PREFIX_XMLNS || prefix == XMLSymbols.EMPTY_STRING
 132                 && localpart == XMLSymbols.PREFIX_XMLNS) {
 133 
 134                 // get the internalized value of this attribute
 135                 String uri = fSymbolTable.addSymbol(attributes.getValue(i));
 136 
 137                 // 1. "xmlns" can't be bound to any namespace
 138                 if (prefix == XMLSymbols.PREFIX_XMLNS && localpart == XMLSymbols.PREFIX_XMLNS) {
 139                     fErrorReporter.reportError(
 140                         XMLMessageFormatter.XMLNS_DOMAIN,
 141                         "CantBindXMLNS",
 142                         new Object[] { attributes.getQName(i)},
 143                         XMLErrorReporter.SEVERITY_FATAL_ERROR);
 144                 }
 145 
 146                 // 2. the namespace for "xmlns" can't be bound to any prefix
 147                 if (uri == NamespaceContext.XMLNS_URI) {
 148                     fErrorReporter.reportError(
 149                         XMLMessageFormatter.XMLNS_DOMAIN,
 150                         "CantBindXMLNS",
 151                         new Object[] { attributes.getQName(i)},
 152                         XMLErrorReporter.SEVERITY_FATAL_ERROR);
 153                 }
 154 
 155                 // 3. "xml" can't be bound to any other namespace than it's own
 156                 if (localpart == XMLSymbols.PREFIX_XML) {
 157                     if (uri != NamespaceContext.XML_URI) {
 158                         fErrorReporter.reportError(
 159                             XMLMessageFormatter.XMLNS_DOMAIN,
 160                             "CantBindXML",
 161                             new Object[] { attributes.getQName(i)},
 162                             XMLErrorReporter.SEVERITY_FATAL_ERROR);
 163                     }
 164                 }
 165                 // 4. the namespace for "xml" can't be bound to any other prefix
 166                 else {
 167                     if (uri == NamespaceContext.XML_URI) {
 168                         fErrorReporter.reportError(
 169                             XMLMessageFormatter.XMLNS_DOMAIN,
 170                             "CantBindXML",
 171                             new Object[] { attributes.getQName(i)},
 172                             XMLErrorReporter.SEVERITY_FATAL_ERROR);
 173                     }
 174                 }
 175 
 176                 prefix = localpart != XMLSymbols.PREFIX_XMLNS ? localpart : XMLSymbols.EMPTY_STRING;
 177 
 178                                 // Declare prefix in context. Removing the association between a prefix and a
 179                                 // namespace name is permitted in XML 1.1, so if the uri value is the empty string,
 180                                 // the prefix is being unbound. -- mrglavas
 181                 fNamespaceContext.declarePrefix(prefix, uri.length() != 0 ? uri : null);
 182             }
 183         }
 184 
 185         // bind the element
 186         String prefix = element.prefix != null ? element.prefix : XMLSymbols.EMPTY_STRING;
 187         element.uri = fNamespaceContext.getURI(prefix);
 188         if (element.prefix == null && element.uri != null) {
 189             element.prefix = XMLSymbols.EMPTY_STRING;
 190         }
 191         if (element.prefix != null && element.uri == null) {
 192             fErrorReporter.reportError(
 193                 XMLMessageFormatter.XMLNS_DOMAIN,
 194                 "ElementPrefixUnbound",
 195                 new Object[] { element.prefix, element.rawname },
 196                 XMLErrorReporter.SEVERITY_FATAL_ERROR);
 197         }
 198 
 199         // bind the attributes
 200         for (int i = 0; i < length; i++) {
 201             attributes.getName(i, fAttributeQName);
 202             String aprefix = fAttributeQName.prefix != null ? fAttributeQName.prefix : XMLSymbols.EMPTY_STRING;
 203             String arawname = fAttributeQName.rawname;
 204             if (arawname == XMLSymbols.PREFIX_XMLNS) {
 205                 fAttributeQName.uri = fNamespaceContext.getURI(XMLSymbols.PREFIX_XMLNS);
 206                 attributes.setName(i, fAttributeQName);
 207             } else if (aprefix != XMLSymbols.EMPTY_STRING) {
 208                 fAttributeQName.uri = fNamespaceContext.getURI(aprefix);
 209                 if (fAttributeQName.uri == null) {
 210                     fErrorReporter.reportError(
 211                         XMLMessageFormatter.XMLNS_DOMAIN,
 212                         "AttributePrefixUnbound",
 213                         new Object[] { element.rawname, arawname, aprefix },
 214                         XMLErrorReporter.SEVERITY_FATAL_ERROR);
 215                 }
 216                 attributes.setName(i, fAttributeQName);
 217             }
 218         }
 219 
 220         // verify that duplicate attributes don't exist
 221         // Example: <foo xmlns:a='NS' xmlns:b='NS' a:attr='v1' b:attr='v2'/>
 222         int attrCount = attributes.getLength();
 223         for (int i = 0; i < attrCount - 1; i++) {
 224             String auri = attributes.getURI(i);
 225             if (auri == null || auri == NamespaceContext.XMLNS_URI) {
 226                 continue;
 227             }
 228             String alocalpart = attributes.getLocalName(i);
 229             for (int j = i + 1; j < attrCount; j++) {
 230                 String blocalpart = attributes.getLocalName(j);
 231                 String buri = attributes.getURI(j);
 232                 if (alocalpart == blocalpart && auri == buri) {
 233                     fErrorReporter.reportError(
 234                         XMLMessageFormatter.XMLNS_DOMAIN,
 235                         "AttributeNSNotUnique",
 236                         new Object[] { element.rawname, alocalpart, auri },
 237                         XMLErrorReporter.SEVERITY_FATAL_ERROR);
 238                 }
 239             }
 240         }
 241 
 242     } // startNamespaceScope(QName,XMLAttributes)
 243 
 244     /** Handles end element. */
 245     protected void endNamespaceScope(QName element, Augmentations augs, boolean isEmpty)
 246         throws XNIException {
 247 
 248         // bind element
 249         String eprefix = element.prefix != null ? element.prefix : XMLSymbols.EMPTY_STRING;
 250         element.uri = fNamespaceContext.getURI(eprefix);
 251         if (element.uri != null) {
 252             element.prefix = eprefix;
 253         }
 254 
 255         // call handlers
 256         if (fDocumentHandler != null) {
 257             if (!isEmpty) {
 258                 fDocumentHandler.endElement(element, augs);
 259             }
 260         }
 261 
 262         // pop context
 263         fNamespaceContext.popContext();
 264 
 265     } // endNamespaceScope(QName,boolean)
 266 }