| 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
/**  | 
 | 
 * Licensed to the Apache Software Foundation (ASF) under one  | 
 | 
 * or more contributor license agreements. See the NOTICE file  | 
 | 
 * distributed with this work for additional information  | 
 | 
 * regarding copyright ownership. The ASF licenses this file  | 
 | 
 * to you 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.  | 
 | 
 */  | 
 | 
/*  | 
 | 
 * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.  | 
 | 
 */  | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
package org.jcp.xml.dsig.internal.dom;  | 
 | 
 | 
 | 
import java.util.*;  | 
 | 
import java.security.spec.AlgorithmParameterSpec;  | 
 | 
import org.w3c.dom.Attr;  | 
 | 
import org.w3c.dom.Document;  | 
 | 
import org.w3c.dom.Element;  | 
 | 
import org.w3c.dom.Node;  | 
 | 
import org.w3c.dom.NodeList;  | 
 | 
 | 
 | 
import javax.xml.XMLConstants;  | 
 | 
import javax.xml.crypto.*;  | 
 | 
import javax.xml.crypto.dsig.*;  | 
 | 
import javax.xml.crypto.dsig.spec.*;  | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
public final class DOMUtils { | 
 | 
 | 
 | 
      | 
 | 
    private DOMUtils() {} | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public static Document getOwnerDocument(Node node) { | 
 | 
        if (node.getNodeType() == Node.DOCUMENT_NODE) { | 
 | 
            return (Document)node;  | 
 | 
        } else { | 
 | 
            return node.getOwnerDocument();  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public static String getQNameString(String prefix, String localName) { | 
 | 
        String qName = prefix == null || prefix.length() == 0  | 
 | 
                ? localName : prefix + ":" + localName;  | 
 | 
 | 
 | 
        return qName;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public static Element createElement(Document doc, String tag,  | 
 | 
                                        String nsURI, String prefix)  | 
 | 
    { | 
 | 
        return doc.createElementNS(nsURI, getQNameString(prefix, tag));  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public static void setAttribute(Element elem, String name, String value) { | 
 | 
        if (value == null) { | 
 | 
            return;  | 
 | 
        }  | 
 | 
        elem.setAttributeNS(null, name, value);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public static void setAttributeID(Element elem, String name, String value) { | 
 | 
        if (value == null) { | 
 | 
            return;  | 
 | 
        }  | 
 | 
        elem.setAttributeNS(null, name, value);  | 
 | 
        elem.setIdAttributeNS(null, name, true);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public static Element getFirstChildElement(Node node) { | 
 | 
        Node child = node.getFirstChild();  | 
 | 
        while (child != null && child.getNodeType() != Node.ELEMENT_NODE) { | 
 | 
            child = child.getNextSibling();  | 
 | 
        }  | 
 | 
        return (Element)child;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    @Deprecated  | 
 | 
    public static Element getFirstChildElement(Node node, String localName)  | 
 | 
        throws MarshalException  | 
 | 
    { | 
 | 
        return verifyElement(getFirstChildElement(node), localName);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public static Element getFirstChildElement(Node node, String localName, String namespaceURI)  | 
 | 
        throws MarshalException  | 
 | 
    { | 
 | 
        return verifyElement(getFirstChildElement(node), localName, namespaceURI);  | 
 | 
    }  | 
 | 
 | 
 | 
    private static Element verifyElement(Element elem, String localName)  | 
 | 
        throws MarshalException  | 
 | 
    { | 
 | 
        if (elem == null) { | 
 | 
            throw new MarshalException("Missing " + localName + " element"); | 
 | 
        }  | 
 | 
        String name = elem.getLocalName();  | 
 | 
        if (!name.equals(localName)) { | 
 | 
            throw new MarshalException("Invalid element name: " + | 
 | 
                                       name + ", expected " + localName);  | 
 | 
        }  | 
 | 
        return elem;  | 
 | 
    }  | 
 | 
 | 
 | 
    private static Element verifyElement(Element elem, String localName, String namespaceURI)  | 
 | 
        throws MarshalException  | 
 | 
    { | 
 | 
        if (elem == null) { | 
 | 
            throw new MarshalException("Missing " + localName + " element"); | 
 | 
        }  | 
 | 
        String name = elem.getLocalName();  | 
 | 
        String namespace = elem.getNamespaceURI();  | 
 | 
        if (!name.equals(localName) || namespace == null && namespaceURI != null  | 
 | 
            || namespace != null && !namespace.equals(namespaceURI)) { | 
 | 
            throw new MarshalException("Invalid element name: " + | 
 | 
                namespace + ":" + name + ", expected " + namespaceURI + ":" + localName);  | 
 | 
        }  | 
 | 
        return elem;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public static Element getLastChildElement(Node node) { | 
 | 
        Node child = node.getLastChild();  | 
 | 
        while (child != null && child.getNodeType() != Node.ELEMENT_NODE) { | 
 | 
            child = child.getPreviousSibling();  | 
 | 
        }  | 
 | 
        return (Element)child;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public static Element getNextSiblingElement(Node node) { | 
 | 
        Node sibling = node.getNextSibling();  | 
 | 
        while (sibling != null && sibling.getNodeType() != Node.ELEMENT_NODE) { | 
 | 
            sibling = sibling.getNextSibling();  | 
 | 
        }  | 
 | 
        return (Element)sibling;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    @Deprecated  | 
 | 
    public static Element getNextSiblingElement(Node node, String localName)  | 
 | 
        throws MarshalException  | 
 | 
    { | 
 | 
        return verifyElement(getNextSiblingElement(node), localName);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public static Element getNextSiblingElement(Node node, String localName, String namespaceURI)  | 
 | 
        throws MarshalException  | 
 | 
    { | 
 | 
        return verifyElement(getNextSiblingElement(node), localName, namespaceURI);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public static String getAttributeValue(Element elem, String name) { | 
 | 
        Attr attr = elem.getAttributeNodeNS(null, name);  | 
 | 
        return (attr == null) ? null : attr.getValue();  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public static <N> String getIdAttributeValue(Element elem, String name) { | 
 | 
        Attr attr = elem.getAttributeNodeNS(null, name);  | 
 | 
        if (attr != null && !attr.isId()) { | 
 | 
            elem.setIdAttributeNode(attr, true);  | 
 | 
        }  | 
 | 
        return (attr == null) ? null : attr.getValue();  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public static Set<Node> nodeSet(NodeList nl) { | 
 | 
        return new NodeSet(nl);  | 
 | 
    }  | 
 | 
 | 
 | 
    static class NodeSet extends AbstractSet<Node> { | 
 | 
        private NodeList nl;  | 
 | 
        public NodeSet(NodeList nl) { | 
 | 
            this.nl = nl;  | 
 | 
        }  | 
 | 
 | 
 | 
        @Override  | 
 | 
        public int size() { return nl.getLength(); } | 
 | 
        @Override  | 
 | 
        public Iterator<Node> iterator() { | 
 | 
            return new Iterator<Node>() { | 
 | 
                private int index;  | 
 | 
 | 
 | 
                @Override  | 
 | 
                public void remove() { | 
 | 
                    throw new UnsupportedOperationException();  | 
 | 
                }  | 
 | 
                @Override  | 
 | 
                public Node next() { | 
 | 
                    if (!hasNext()) { | 
 | 
                        throw new NoSuchElementException();  | 
 | 
                    }  | 
 | 
                    return nl.item(index++);  | 
 | 
                }  | 
 | 
                @Override  | 
 | 
                public boolean hasNext() { | 
 | 
                    return index < nl.getLength();  | 
 | 
                }  | 
 | 
            };  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public static String getNSPrefix(XMLCryptoContext context, String nsURI) { | 
 | 
        if (context != null) { | 
 | 
            return context.getNamespacePrefix  | 
 | 
                (nsURI, context.getDefaultNamespacePrefix());  | 
 | 
        } else { | 
 | 
            return null;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public static String getSignaturePrefix(XMLCryptoContext context) { | 
 | 
        return getNSPrefix(context, XMLSignature.XMLNS);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public static void removeAllChildren(Node node) { | 
 | 
        Node firstChild = node.getFirstChild();  | 
 | 
        while (firstChild != null) { | 
 | 
            Node nodeToRemove = firstChild;  | 
 | 
            firstChild = firstChild.getNextSibling();  | 
 | 
            node.removeChild(nodeToRemove);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    public static boolean nodesEqual(Node thisNode, Node otherNode) { | 
 | 
        if (thisNode == otherNode) { | 
 | 
            return true;  | 
 | 
        }  | 
 | 
        if (thisNode.getNodeType() != otherNode.getNodeType()) { | 
 | 
            return false;  | 
 | 
        }  | 
 | 
          | 
 | 
        return true;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public static void appendChild(Node parent, Node child) { | 
 | 
        Document ownerDoc = getOwnerDocument(parent);  | 
 | 
        if (child.getOwnerDocument() != ownerDoc) { | 
 | 
            parent.appendChild(ownerDoc.importNode(child, true));  | 
 | 
        } else { | 
 | 
            parent.appendChild(child);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    public static boolean paramsEqual(AlgorithmParameterSpec spec1,  | 
 | 
        AlgorithmParameterSpec spec2) { | 
 | 
        if (spec1 == spec2) { | 
 | 
            return true;  | 
 | 
        }  | 
 | 
        if (spec1 instanceof XPathFilter2ParameterSpec &&  | 
 | 
            spec2 instanceof XPathFilter2ParameterSpec) { | 
 | 
            return paramsEqual((XPathFilter2ParameterSpec)spec1,  | 
 | 
                               (XPathFilter2ParameterSpec)spec2);  | 
 | 
        }  | 
 | 
        if (spec1 instanceof ExcC14NParameterSpec &&  | 
 | 
            spec2 instanceof ExcC14NParameterSpec) { | 
 | 
            return paramsEqual((ExcC14NParameterSpec) spec1,  | 
 | 
                               (ExcC14NParameterSpec)spec2);  | 
 | 
        }  | 
 | 
        if (spec1 instanceof XPathFilterParameterSpec &&  | 
 | 
            spec2 instanceof XPathFilterParameterSpec) { | 
 | 
            return paramsEqual((XPathFilterParameterSpec)spec1,  | 
 | 
                               (XPathFilterParameterSpec)spec2);  | 
 | 
        }  | 
 | 
        if (spec1 instanceof XSLTTransformParameterSpec &&  | 
 | 
            spec2 instanceof XSLTTransformParameterSpec) { | 
 | 
            return paramsEqual((XSLTTransformParameterSpec)spec1,  | 
 | 
                               (XSLTTransformParameterSpec)spec2);  | 
 | 
        }  | 
 | 
        return false;  | 
 | 
    }  | 
 | 
 | 
 | 
    private static boolean paramsEqual(XPathFilter2ParameterSpec spec1,  | 
 | 
                                       XPathFilter2ParameterSpec spec2)  | 
 | 
    { | 
 | 
        @SuppressWarnings("unchecked") | 
 | 
        List<XPathType> types = spec1.getXPathList();  | 
 | 
        @SuppressWarnings("unchecked") | 
 | 
        List<XPathType> otypes = spec2.getXPathList();  | 
 | 
        int size = types.size();  | 
 | 
        if (size != otypes.size()) { | 
 | 
            return false;  | 
 | 
        }  | 
 | 
        for (int i = 0; i < size; i++) { | 
 | 
            XPathType type = types.get(i);  | 
 | 
            XPathType otype = otypes.get(i);  | 
 | 
            if (!type.getExpression().equals(otype.getExpression()) ||  | 
 | 
                !type.getNamespaceMap().equals(otype.getNamespaceMap()) ||  | 
 | 
                type.getFilter() != otype.getFilter()) { | 
 | 
                return false;  | 
 | 
            }  | 
 | 
        }  | 
 | 
        return true;  | 
 | 
    }  | 
 | 
 | 
 | 
    private static boolean paramsEqual(ExcC14NParameterSpec spec1,  | 
 | 
                                       ExcC14NParameterSpec spec2)  | 
 | 
    { | 
 | 
        return spec1.getPrefixList().equals(spec2.getPrefixList());  | 
 | 
    }  | 
 | 
 | 
 | 
    private static boolean paramsEqual(XPathFilterParameterSpec spec1,  | 
 | 
                                       XPathFilterParameterSpec spec2)  | 
 | 
    { | 
 | 
        return spec1.getXPath().equals(spec2.getXPath()) &&  | 
 | 
                spec1.getNamespaceMap().equals(spec2.getNamespaceMap());  | 
 | 
    }  | 
 | 
 | 
 | 
    private static boolean paramsEqual(XSLTTransformParameterSpec spec1,  | 
 | 
                                       XSLTTransformParameterSpec spec2)  | 
 | 
    { | 
 | 
 | 
 | 
        XMLStructure ostylesheet = spec2.getStylesheet();  | 
 | 
        if (!(ostylesheet instanceof javax.xml.crypto.dom.DOMStructure)) { | 
 | 
            return false;  | 
 | 
        }  | 
 | 
        Node ostylesheetElem =  | 
 | 
            ((javax.xml.crypto.dom.DOMStructure) ostylesheet).getNode();  | 
 | 
        XMLStructure stylesheet = spec1.getStylesheet();  | 
 | 
        Node stylesheetElem =  | 
 | 
            ((javax.xml.crypto.dom.DOMStructure) stylesheet).getNode();  | 
 | 
        return nodesEqual(stylesheetElem, ostylesheetElem);  | 
 | 
    }  | 
 | 
 | 
 | 
    public static boolean isNamespace(Node node)  | 
 | 
    { | 
 | 
        final short nodeType = node.getNodeType();  | 
 | 
        if (nodeType == Node.ATTRIBUTE_NODE) { | 
 | 
            final String namespaceURI = node.getNamespaceURI();  | 
 | 
            return XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceURI);  | 
 | 
        }  | 
 | 
        return false;  | 
 | 
    }  | 
 | 
}  |