--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/org/apache/xml/internal/security/utils/XMLUtils.java Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,697 @@
+/*
+ * reserved comment block
+ * DO NOT REMOVE OR ALTER!
+ */
+
+/*
+ * 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.utils;
+
+
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import com.sun.org.apache.xml.internal.security.c14n.CanonicalizationException;
+import com.sun.org.apache.xml.internal.security.c14n.Canonicalizer;
+import com.sun.org.apache.xml.internal.security.c14n.InvalidCanonicalizerException;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Text;
+
+
+
+/**
+ * DOM and XML accessibility and comfort functions.
+ *
+ * @author Christian Geuer-Pollmann
+ */
+public class XMLUtils {
+
+ /**
+ * Constructor XMLUtils
+ *
+ */
+ private XMLUtils() {
+
+ // we don't allow instantiation
+ }
+
+
+ /**
+ * @param rootNode
+ * @param result
+ * @param exclude
+ * @param com wheather comments or not
+ */
+ public static void getSet(Node rootNode,Set result,Node exclude ,boolean com) {
+ if ((exclude!=null) && isDescendantOrSelf(exclude,rootNode)){
+ return;
+ }
+ getSetRec(rootNode,result,exclude,com);
+ }
+ static final void getSetRec(final Node rootNode,final Set result,
+ final Node exclude ,final boolean com) {
+ //Set result = new HashSet();
+ if (rootNode==exclude) {
+ return;
+ }
+ switch (rootNode.getNodeType()) {
+ case Node.ELEMENT_NODE:
+ result.add(rootNode);
+ Element el=(Element)rootNode;
+ if (el.hasAttributes()) {
+ NamedNodeMap nl = ((Element)rootNode).getAttributes();
+ for (int i=0;i<nl.getLength();i++) {
+ result.add(nl.item(i));
+ }
+ }
+ //no return keep working
+ case Node.DOCUMENT_NODE:
+ for (Node r=rootNode.getFirstChild();r!=null;r=r.getNextSibling()){
+ if (r.getNodeType()==Node.TEXT_NODE) {
+ result.add(r);
+ while ((r!=null) && (r.getNodeType()==Node.TEXT_NODE)) {
+ r=r.getNextSibling();
+ }
+ if (r==null)
+ return;
+ }
+ getSetRec(r,result,exclude,com);
+ }
+ return;
+ case Node.COMMENT_NODE:
+ if (com) {
+ result.add(rootNode);
+ }
+ return;
+ case Node.DOCUMENT_TYPE_NODE:
+ return;
+ default:
+ result.add(rootNode);
+ }
+ return;
+ }
+
+
+ /**
+ * Outputs a DOM tree to an {@link OutputStream}.
+ *
+ * @param contextNode root node of the DOM tree
+ * @param os the {@link OutputStream}
+ */
+ public static void outputDOM(Node contextNode, OutputStream os) {
+ XMLUtils.outputDOM(contextNode, os, false);
+ }
+
+ /**
+ * Outputs a DOM tree to an {@link OutputStream}. <I>If an Exception is
+ * thrown during execution, it's StackTrace is output to System.out, but the
+ * Exception is not re-thrown.</I>
+ *
+ * @param contextNode root node of the DOM tree
+ * @param os the {@link OutputStream}
+ * @param addPreamble
+ */
+ public static void outputDOM(Node contextNode, OutputStream os,
+ boolean addPreamble) {
+
+ try {
+ if (addPreamble) {
+ os.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n".getBytes());
+ }
+
+ os.write(
+ Canonicalizer.getInstance(
+ Canonicalizer.ALGO_ID_C14N_WITH_COMMENTS).canonicalizeSubtree(
+ contextNode));
+ } catch (IOException ex) {}
+ catch (InvalidCanonicalizerException ex) {
+ ex.printStackTrace();
+ } catch (CanonicalizationException ex) {
+ ex.printStackTrace();
+ }
+ }
+
+ /**
+ * Serializes the <CODE>contextNode</CODE> into the OutputStream, <I>but
+ * supresses all Exceptions</I>.
+ * <BR />
+ * NOTE: <I>This should only be used for debugging purposes,
+ * NOT in a production environment; this method ignores all exceptions,
+ * so you won't notice if something goes wrong. If you're asking what is to
+ * be used in a production environment, simply use the code inside the
+ * <code>try{}</code> statement, but handle the Exceptions appropriately.</I>
+ *
+ * @param contextNode
+ * @param os
+ */
+ public static void outputDOMc14nWithComments(Node contextNode,
+ OutputStream os) {
+
+ try {
+ os.write(
+ Canonicalizer.getInstance(
+ Canonicalizer.ALGO_ID_C14N_WITH_COMMENTS).canonicalizeSubtree(
+ contextNode));
+ } catch (IOException ex) {
+
+ // throw new RuntimeException(ex.getMessage());
+ } catch (InvalidCanonicalizerException ex) {
+
+ // throw new RuntimeException(ex.getMessage());
+ } catch (CanonicalizationException ex) {
+
+ // throw new RuntimeException(ex.getMessage());
+ }
+ }
+
+
+ /**
+ * Method getFullTextChildrenFromElement
+ *
+ * @param element
+ * @return the string of chi;ds
+ */
+ public static String getFullTextChildrenFromElement(Element element) {
+
+ StringBuffer sb = new StringBuffer();
+ NodeList children = element.getChildNodes();
+ int iMax = children.getLength();
+
+ for (int i = 0; i < iMax; i++) {
+ Node curr = children.item(i);
+
+ if (curr.getNodeType() == Node.TEXT_NODE) {
+ sb.append(((Text) curr).getData());
+ }
+ }
+
+ return sb.toString();
+ }
+
+
+ /**
+ * Creates an Element in the XML Signature specification namespace.
+ *
+ * @param doc the factory Document
+ * @param elementName the local name of the Element
+ * @return the Element
+ */
+ public static Element createElementInSignatureSpace(Document doc,
+ String elementName) {
+
+ if (doc == null) {
+ throw new RuntimeException("Document is null");
+ }
+
+ String ds = Constants.getSignatureSpecNSprefix();
+
+ if ((ds == null) || (ds.length() == 0)) {
+ Element element = doc.createElementNS(Constants.SignatureSpecNS,
+ elementName);
+
+ element.setAttributeNS(Constants.NamespaceSpecNS, "xmlns",
+ Constants.SignatureSpecNS);
+
+ return element;
+ }
+ Element element = doc.createElementNS(Constants.SignatureSpecNS,
+ ds + ":" + elementName);
+
+ element.setAttributeNS(Constants.NamespaceSpecNS, "xmlns:" + ds,
+ Constants.SignatureSpecNS);
+
+ return element;
+
+ }
+
+
+ /**
+ * Returns true if the element is in XML Signature namespace and the local
+ * name equals the supplied one.
+ *
+ * @param element
+ * @param localName
+ * @return true if the element is in XML Signature namespace and the local name equals the supplied one
+ */
+ public static boolean elementIsInSignatureSpace(Element element,
+ String localName) {
+
+ if ((element == null) ||
+ !Constants.SignatureSpecNS.equals(element.getNamespaceURI()) ){
+ return false;
+ }
+
+ if (!element.getLocalName().equals(localName)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns true if the element is in XML Encryption namespace and the local
+ * name equals the supplied one.
+ *
+ * @param element
+ * @param localName
+ * @return true if the element is in XML Encryption namespace and the local name equals the supplied one
+ */
+ public static boolean elementIsInEncryptionSpace(Element element,
+ String localName) {
+
+ if ((element == null) ||
+ !EncryptionConstants.EncryptionSpecNS.equals(element.getNamespaceURI())
+ ){
+ return false;
+ }
+
+ if (!element.getLocalName().equals(localName)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * This method returns the owner document of a particular node.
+ * This method is necessary because it <I>always</I> returns a
+ * {@link Document}. {@link Node#getOwnerDocument} returns <CODE>null</CODE>
+ * if the {@link Node} is a {@link Document}.
+ *
+ * @param node
+ * @return the owner document of the node
+ */
+ public static Document getOwnerDocument(Node node) {
+
+ if (node.getNodeType() == Node.DOCUMENT_NODE) {
+ return (Document) node;
+ }
+ try {
+ return node.getOwnerDocument();
+ } catch (NullPointerException npe) {
+ throw new NullPointerException(I18n.translate("endorsed.jdk1.4.0")
+ + " Original message was \""
+ + npe.getMessage() + "\"");
+ }
+
+ }
+
+ /**
+ * This method returns the first non-null owner document of the Node's in this Set.
+ * This method is necessary because it <I>always</I> returns a
+ * {@link Document}. {@link Node#getOwnerDocument} returns <CODE>null</CODE>
+ * if the {@link Node} is a {@link Document}.
+ *
+ * @param xpathNodeSet
+ * @return the owner document
+ */
+ public static Document getOwnerDocument(Set xpathNodeSet) {
+ NullPointerException npe = null;
+ Iterator iterator = xpathNodeSet.iterator();
+ while(iterator.hasNext()) {
+ Node node = (Node) iterator.next();
+ int nodeType =node.getNodeType();
+ if (nodeType == Node.DOCUMENT_NODE) {
+ return (Document) node;
+ }
+ try {
+ if (nodeType==Node.ATTRIBUTE_NODE) {
+ return ((Attr)node).getOwnerElement().getOwnerDocument();
+ }
+ return node.getOwnerDocument();
+ } catch (NullPointerException e) {
+ npe = e;
+ }
+
+ }
+ throw new NullPointerException(I18n.translate("endorsed.jdk1.4.0")
+ + " Original message was \""
+ + (npe == null ? "" : npe.getMessage()) + "\"");
+ }
+
+
+
+ /**
+ * Method createDSctx
+ *
+ * @param doc
+ * @param prefix
+ * @param namespace
+ * @return the element.
+ */
+ public static Element createDSctx(Document doc, String prefix,
+ String namespace) {
+
+ if ((prefix == null) || (prefix.trim().length() == 0)) {
+ throw new IllegalArgumentException("You must supply a prefix");
+ }
+
+ Element ctx = doc.createElementNS(null, "namespaceContext");
+
+ ctx.setAttributeNS(Constants.NamespaceSpecNS, "xmlns:" + prefix.trim(),
+ namespace);
+
+ return ctx;
+ }
+
+
+
+ /**
+ * Method addReturnToElement
+ *
+ * @param e
+ */
+ public static void addReturnToElement(Element e) {
+
+ Document doc = e.getOwnerDocument();
+
+ e.appendChild(doc.createTextNode("\n"));
+ }
+
+ /**
+ * Method convertNodelistToSet
+ *
+ * @param xpathNodeSet
+ * @return the set with the nodelist
+ */
+ public static Set convertNodelistToSet(NodeList xpathNodeSet) {
+
+ if (xpathNodeSet == null) {
+ return new HashSet();
+ }
+
+ int length = xpathNodeSet.getLength();
+ Set set = new HashSet(length);
+
+ for (int i = 0; i < length; i++) {
+ set.add(xpathNodeSet.item(i));
+ }
+
+ return set;
+ }
+
+
+ /**
+ * This method spreads all namespace attributes in a DOM document to their
+ * children. This is needed because the XML Signature XPath transform
+ * must evaluate the XPath against all nodes in the input, even against
+ * XPath namespace nodes. Through a bug in XalanJ2, the namespace nodes are
+ * not fully visible in the Xalan XPath model, so we have to do this by
+ * hand in DOM spaces so that the nodes become visible in XPath space.
+ *
+ * @param doc
+ * @see <A HREF="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=2650">Namespace axis resolution is not XPath compliant </A>
+ */
+ public static void circumventBug2650(Document doc) {
+
+ Element documentElement = doc.getDocumentElement();
+
+ // if the document element has no xmlns definition, we add xmlns=""
+ Attr xmlnsAttr =
+ documentElement.getAttributeNodeNS(Constants.NamespaceSpecNS, "xmlns");
+
+ if (xmlnsAttr == null) {
+ documentElement.setAttributeNS(Constants.NamespaceSpecNS, "xmlns", "");
+ }
+
+ XMLUtils.circumventBug2650internal(doc);
+ }
+
+ /**
+ * This is the work horse for {@link #circumventBug2650}.
+ *
+ * @param node
+ * @see <A HREF="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=2650">Namespace axis resolution is not XPath compliant </A>
+ */
+ private static void circumventBug2650internal(Node node) {
+ Node parent=null;
+ Node sibling=null;
+ final String namespaceNs=Constants.NamespaceSpecNS;
+ do {
+ switch (node.getNodeType()) {
+ case Node.ELEMENT_NODE :
+ Element element = (Element) node;
+ if (!element.hasChildNodes())
+ break;
+ if (element.hasAttributes()) {
+ NamedNodeMap attributes = element.getAttributes();
+ int attributesLength = attributes.getLength();
+
+ for (Node child = element.getFirstChild(); child!=null;
+ child=child.getNextSibling()) {
+
+ if (child.getNodeType() != Node.ELEMENT_NODE) {
+ continue;
+ }
+ Element childElement = (Element) child;
+
+ for (int i = 0; i < attributesLength; i++) {
+ Attr currentAttr = (Attr) attributes.item(i);
+ if (!namespaceNs.equals(currentAttr.getNamespaceURI()))
+ continue;
+ if (childElement.hasAttributeNS(namespaceNs,
+ currentAttr.getLocalName())) {
+ continue;
+ }
+ childElement.setAttributeNS(namespaceNs,
+ currentAttr.getName(),
+ currentAttr.getNodeValue());
+
+
+ }
+ }
+ }
+ case Node.ENTITY_REFERENCE_NODE :
+ case Node.DOCUMENT_NODE :
+ parent=node;
+ sibling=node.getFirstChild();
+ break;
+ }
+ while ((sibling==null) && (parent!=null)) {
+ sibling=parent.getNextSibling();
+ parent=parent.getParentNode();
+ };
+ if (sibling==null) {
+ return;
+ }
+
+ node=sibling;
+ sibling=node.getNextSibling();
+ } while (true);
+ }
+
+ /**
+ * @param sibling
+ * @param nodeName
+ * @param number
+ * @return nodes with the constrain
+ */
+ public static Element selectDsNode(Node sibling, String nodeName, int number) {
+ while (sibling!=null) {
+ if (nodeName.equals(sibling.getLocalName())
+ && Constants.SignatureSpecNS.equals(sibling.getNamespaceURI())) {
+ if (number==0){
+ return (Element)sibling;
+ }
+ number--;
+ }
+ sibling=sibling.getNextSibling();
+ }
+ return null;
+ }
+
+ /**
+ * @param sibling
+ * @param nodeName
+ * @param number
+ * @return nodes with the constrain
+ */
+
+ public static Element selectXencNode(Node sibling, String nodeName, int number) {
+ while (sibling!=null) {
+ if (nodeName.equals(sibling.getLocalName())
+ && EncryptionConstants.EncryptionSpecNS.equals(sibling.getNamespaceURI())) {
+ if (number==0){
+ return (Element)sibling;
+ }
+ number--;
+ }
+ sibling=sibling.getNextSibling();
+ }
+ return null;
+ }
+
+
+ /**
+ * @param sibling
+ * @param nodeName
+ * @param number
+ * @return nodes with the constrain
+ */
+ public static Text selectDsNodeText(Node sibling, String nodeName, int number) {
+ Node n=selectDsNode(sibling,nodeName,number);
+ if (n==null) {
+ return null;
+ }
+ n=n.getFirstChild();
+ while (n!=null && n.getNodeType()!=Node.TEXT_NODE) {
+ n=n.getNextSibling();
+ }
+ return (Text)n;
+ }
+
+ /**
+ * @param sibling
+ * @param uri
+ * @param nodeName
+ * @param number
+ * @return nodes with the constrain
+ */
+ public static Text selectNodeText(Node sibling, String uri, String nodeName, int number) {
+ Node n=selectNode(sibling,uri,nodeName,number);
+ if (n==null) {
+ return null;
+ }
+ n=n.getFirstChild();
+ while (n!=null && n.getNodeType()!=Node.TEXT_NODE) {
+ n=n.getNextSibling();
+ }
+ return (Text)n;
+ }
+
+ /**
+ * @param sibling
+ * @param uri
+ * @param nodeName
+ * @param number
+ * @return nodes with the constrain
+ */
+ public static Element selectNode(Node sibling, String uri,String nodeName, int number) {
+ while (sibling!=null) {
+ if (nodeName.equals(sibling.getLocalName())
+ && uri.equals(sibling.getNamespaceURI())) {
+ if (number==0){
+ return (Element)sibling;
+ }
+ number--;
+ }
+ sibling=sibling.getNextSibling();
+ }
+ return null;
+ }
+
+ /**
+ * @param sibling
+ * @param nodeName
+ * @return nodes with the constrain
+ */
+ public static Element[] selectDsNodes(Node sibling,String nodeName) {
+ return selectNodes(sibling,Constants.SignatureSpecNS,nodeName);
+ }
+
+ /**
+ * @param sibling
+ * @param uri
+ * @param nodeName
+ * @return nodes with the constrain
+ */
+ public static Element[] selectNodes(Node sibling,String uri,String nodeName) {
+ int size=20;
+ Element[] a= new Element[size];
+ int curr=0;
+ //List list=new ArrayList();
+ while (sibling!=null) {
+ if (nodeName.equals(sibling.getLocalName())
+ && uri.equals(sibling.getNamespaceURI())) {
+ a[curr++]=(Element)sibling;
+ if (size<=curr) {
+ int cursize= size<<2;
+ Element []cp=new Element[cursize];
+ System.arraycopy(a,0,cp,0,size);
+ a=cp;
+ size=cursize;
+ }
+ }
+ sibling=sibling.getNextSibling();
+ }
+ Element []af=new Element[curr];
+ System.arraycopy(a,0,af,0,curr);
+ return af;
+ }
+
+ /**
+ * @param signatureElement
+ * @param inputSet
+ * @return nodes with the constrain
+ */
+ public static Set excludeNodeFromSet(Node signatureElement, Set inputSet) {
+ Set resultSet = new HashSet();
+ Iterator iterator = inputSet.iterator();
+
+ while (iterator.hasNext()) {
+ Node inputNode = (Node) iterator.next();
+
+ if (!XMLUtils
+ .isDescendantOrSelf(signatureElement, inputNode)) {
+ resultSet.add(inputNode);
+ }
+ }
+ return resultSet;
+ }
+
+ /**
+ * Returns true if the descendantOrSelf is on the descendant-or-self axis
+ * of the context node.
+ *
+ * @param ctx
+ * @param descendantOrSelf
+ * @return true if the node is descendant
+ */
+ static public boolean isDescendantOrSelf(Node ctx, Node descendantOrSelf) {
+
+ if (ctx == descendantOrSelf) {
+ return true;
+ }
+
+ Node parent = descendantOrSelf;
+
+ while (true) {
+ if (parent == null) {
+ return false;
+ }
+
+ if (parent == ctx) {
+ return true;
+ }
+
+ if (parent.getNodeType() == Node.ATTRIBUTE_NODE) {
+ parent = ((Attr) parent).getOwnerElement();
+ } else {
+ parent = parent.getParentNode();
+ }
+ }
+ }
+}