FileDocCategorySizeDatePackage
Canonicalizer20010315.javaAPI DocJava SE 6 API13259Tue Jun 10 00:23:00 BST 2008com.sun.org.apache.xml.internal.security.c14n.implementations

Canonicalizer20010315.java

/*
 * Copyright  1999-2004 The Apache Software Foundation.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */
package com.sun.org.apache.xml.internal.security.c14n.implementations;



import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

import com.sun.org.apache.xml.internal.security.c14n.CanonicalizationException;
import com.sun.org.apache.xml.internal.security.c14n.helper.C14nHelper;
import com.sun.org.apache.xml.internal.security.utils.Constants;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;


/**
 * Implements <A HREF="http://www.w3.org/TR/2001/REC-xml-c14n-20010315">Canonical
 * XML Version 1.0</A>, a W3C Recommendation from 15 March 2001.
 *
 * @author Christian Geuer-Pollmann <geuerp@apache.org>
 * @version $Revision: 1.37 $
 */
public abstract class Canonicalizer20010315 extends CanonicalizerBase {
	boolean firstCall=true;
	final SortedSet result= new TreeSet(COMPARE);
    static final String XMLNS_URI=Constants.NamespaceSpecNS;
    static final String XML_LANG_URI=Constants.XML_LANG_SPACE_SpecNS;
   /**
    * Constructor Canonicalizer20010315
    *
    * @param includeComments
    */
   public Canonicalizer20010315(boolean includeComments) {
      super(includeComments);
   }

   /**
    * Returns the Attr[]s to be outputted for the given element.
    * <br>
    * The code of this method is a copy of {@link #handleAttributes(Element,
    * NameSpaceSymbTable)},
    * whereas it takes into account that subtree-c14n is -- well -- subtree-based.
    * So if the element in question isRoot of c14n, it's parent is not in the
    * node set, as well as all other ancestors.
    *
    * @param E
    * @param ns
    * @return the Attr[]s to be outputted
    * @throws CanonicalizationException
    */
   Iterator handleAttributesSubtree(Element E,  NameSpaceSymbTable ns )
           throws CanonicalizationException {
   	  if (!E.hasAttributes() && !firstCall) {
         return null; 
      }
      // result will contain the attrs which have to be outputted   	  
      final SortedSet result = this.result;       
      result.clear();
      NamedNodeMap attrs = E.getAttributes();
      int attrsLength = attrs.getLength();      
            
      for (int i = 0; i < attrsLength; i++) {
         Attr N = (Attr) attrs.item(i);
         String NName=N.getLocalName();
         String NValue=N.getValue();
         String NUri =N.getNamespaceURI();

         if (!XMLNS_URI.equals(NUri)) {
         	//It's not a namespace attr node. Add to the result and continue.
            result.add(N);
            continue;
         }
         
         if (XML.equals(NName)
                 && XML_LANG_URI.equals(NValue)) {
         	//The default mapping for xml must not be output.
         	continue;
         }
         
         Node n=ns.addMappingAndRender(NName,NValue,N);          		 
		 	 
      	  if (n!=null) {
      	  	 //Render the ns definition
             result.add(n);
             if (C14nHelper.namespaceIsRelative(N)) {
                Object exArgs[] = { E.getTagName(), NName, N.getNodeValue() };
                throw new CanonicalizationException(
                   "c14n.Canonicalizer.RelativeNamespace", exArgs);
             }
          }        
      }
            	   
      if (firstCall) {
      	//It is the first node of the subtree
      	//Obtain all the namespaces defined in the parents, and added to the output.
      	ns.getUnrenderedNodes(result);          	      		            
      	//output the attributes in the xml namespace.
		addXmlAttributesSubtree(E, result);
        firstCall=false;
      } 
      
      return result.iterator();
   }

   /**
    * Float the xml:* attributes of the parent nodes to the root node of c14n
    * @param E the root node.
    * @param result the xml:* attributes  to output.
    */
   private void addXmlAttributesSubtree(Element E, SortedSet result) {
         // E is in the node-set
         Node parent = E.getParentNode();
         Map loa = new HashMap();

         if ((parent != null) && (parent.getNodeType() == Node.ELEMENT_NODE)) {

            // parent element is not in node set
            for (Node ancestor = parent;
                    (ancestor != null)
                    && (ancestor.getNodeType() == Node.ELEMENT_NODE);
                    ancestor = ancestor.getParentNode()) {
               Element el=((Element) ancestor);
               if (!el.hasAttributes()) {
                    continue;
               }
               // for all ancestor elements
               NamedNodeMap ancestorAttrs = el.getAttributes();

               for (int i = 0; i < ancestorAttrs.getLength(); i++) {
                  // for all attributes in the ancestor element
                  Attr currentAncestorAttr = (Attr) ancestorAttrs.item(i);

                  if (XML_LANG_URI.equals(
                          currentAncestorAttr.getNamespaceURI())) {

                     // do we have an xml:* ?
                     if (!E.hasAttributeNS(
                             XML_LANG_URI,
                             currentAncestorAttr.getLocalName())) {

                        // the xml:* attr is not in E
                        if (!loa.containsKey(currentAncestorAttr.getName())) {
                           loa.put(currentAncestorAttr.getName(),
                                   currentAncestorAttr);
                        }
                     }
                  }
               }
            }
         }

         result.addAll( loa.values());
         
      }

   /**
    * Returns the Attr[]s to be outputted for the given element.
    * <br>
    * IMPORTANT: This method expects to work on a modified DOM tree, i.e. a DOM which has
    * been prepared using {@link com.sun.org.apache.xml.internal.security.utils.XMLUtils#circumventBug2650(
    * org.w3c.dom.Document)}.
    * 
    * @param E
    * @param ns
    * @return the Attr[]s to be outputted
    * @throws CanonicalizationException
    */
   Iterator handleAttributes(Element E,  NameSpaceSymbTable ns ) throws CanonicalizationException {    
    // result will contain the attrs which have to be outputted
    boolean isRealVisible=isVisible(E);    
    NamedNodeMap attrs = null;
    int attrsLength = 0;
    if (E.hasAttributes()) {
        attrs=E.getAttributes();
       attrsLength= attrs.getLength();
    }
    
    
    SortedSet result = this.result;       
    result.clear();
    
            
    for (int i = 0; i < attrsLength; i++) {
       Attr N = (Attr) attrs.item(i);
       String NName=N.getLocalName();
       String NValue=N.getValue();
       String NUri =N.getNamespaceURI();
       
       if (!XMLNS_URI.equals(NUri)) {
       	  //A non namespace definition node.
       	  if (isRealVisible){
       		//The node is visible add the attribute to the list of output attributes.
           	result.add(N);
          }
       	  //keep working
          continue;
       }

              
       if ("xml".equals(NName)
               && XML_LANG_URI.equals(NValue)) {
          /* except omit namespace node with local name xml, which defines
           * the xml prefix, if its string value is http://www.w3.org/XML/1998/namespace.
           */
          continue;
       }
       //add the prefix binding to the ns symb table.
       //ns.addInclusiveMapping(NName,NValue,N,isRealVisible);          
	    if  (isVisible(N))  {
			    //The xpath select this node output it if needed.
	    		Node n=ns.addMappingAndRenderXNodeSet(NName,NValue,N,isRealVisible); 	    		
		 	 	if (n!=null) {
		 	 		result.add(n);
                    if (C14nHelper.namespaceIsRelative(N)) {
                       Object exArgs[] = { E.getTagName(), NName, N.getNodeValue() };
                       throw new CanonicalizationException(
                          "c14n.Canonicalizer.RelativeNamespace", exArgs);
                    }
		 	 	}
    	}
    }
    if (isRealVisible) {    	           
    	//The element is visible, handle the xmlns definition        
        Attr xmlns = E.getAttributeNodeNS(XMLNS_URI, XMLNS);
        Node n=null;
        if (xmlns == null) {
        	//No xmlns def just get the already defined.
        	n=ns.getMapping(XMLNS);        		
        } else if ( !isVisible(xmlns)) {
        	//There is a definition but the xmlns is not selected by the xpath.
        	//then xmlns=""
        	n=ns.addMappingAndRenderXNodeSet(XMLNS,"",nullNode,true);        	    		      	
        }
        //output the xmlns def if needed.
        if (n!=null) {
    			result.add(n);
    	}
        //Float all xml:* attributes of the unselected parent elements to this one. 
    	addXmlAttributes(E,result);
    }
    
    return result.iterator();
   }
   /**
    *  Float the xml:* attributes of the unselected parent nodes to the ciurrent node.
    * @param E
    * @param result
    */
   private void addXmlAttributes(Element E, SortedSet result) {
	/* The processing of an element node E MUST be modified slightly when an
       * XPath node-set is given as input and the element's parent is omitted
       * from the node-set. The method for processing the attribute axis of an
       * element E in the node-set is enhanced. All element nodes along E's
       * ancestor axis are examined for nearest occurrences of attributes in
       * the xml namespace, such as xml:lang and xml:space (whether or not they
       * are in the node-set). From this list of attributes, remove any that are
       * in E's attribute axis (whether or not they are in the node-set). Then,
       * lexicographically merge this attribute list with the nodes of E's
       * attribute axis that are in the node-set. The result of visiting the
       * attribute axis is computed by processing the attribute nodes in this
       * merged attribute list.
       */
      
         // E is in the node-set
         Node parent = E.getParentNode();
         Map loa = new HashMap();

         if ((parent != null) && (parent.getNodeType() == Node.ELEMENT_NODE)
                 &&!isVisible(parent)) {

            // parent element is not in node set
            for (Node ancestor = parent;
                    (ancestor != null)
                    && (ancestor.getNodeType() == Node.ELEMENT_NODE);
                    ancestor = ancestor.getParentNode()) {
            	Element el=((Element) ancestor);
                if (!el.hasAttributes()) {
                	continue;
                }
               // for all ancestor elements
               NamedNodeMap ancestorAttrs =el.getAttributes();

               for (int i = 0; i < ancestorAttrs.getLength(); i++) {

                  // for all attributes in the ancestor element
                  Attr currentAncestorAttr = (Attr) ancestorAttrs.item(i);

                  if (XML_LANG_URI.equals(
                          currentAncestorAttr.getNamespaceURI())) {

                     // do we have an xml:* ?
                     if (!E.hasAttributeNS(
                             XML_LANG_URI,
                             currentAncestorAttr.getLocalName())) {

                        // the xml:* attr is not in E
                        if (!loa.containsKey(currentAncestorAttr.getName())) {
                           loa.put(currentAncestorAttr.getName(),
                                   currentAncestorAttr);
                        }
                     }
                  }
               }
            }
         }
         result.addAll(loa.values());
               
}

   /**
    * Always throws a CanonicalizationException because this is inclusive c14n.
    *
    * @param xpathNodeSet
    * @param inclusiveNamespaces
    * @return none it always fails
    * @throws CanonicalizationException always
    */
   public byte[] engineCanonicalizeXPathNodeSet(Set xpathNodeSet, String inclusiveNamespaces)
           throws CanonicalizationException {

      /** $todo$ well, should we throw UnsupportedOperationException ? */
      throw new CanonicalizationException(
         "c14n.Canonicalizer.UnsupportedOperation");
   }

   /**
    * Always throws a CanonicalizationException because this is inclusive c14n.
    *
    * @param rootNode
    * @param inclusiveNamespaces
    * @return none it always fails
    * @throws CanonicalizationException
    */
   public byte[] engineCanonicalizeSubTree(Node rootNode, String inclusiveNamespaces)
           throws CanonicalizationException {

      /** $todo$ well, should we throw UnsupportedOperationException ? */
      throw new CanonicalizationException(
         "c14n.Canonicalizer.UnsupportedOperation");
   }
}