1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 /**
   6  * Licensed to the Apache Software Foundation (ASF) under one
   7  * or more contributor license agreements. See the NOTICE file
   8  * distributed with this work for additional information
   9  * regarding copyright ownership. The ASF licenses this file
  10  * to you under the Apache License, Version 2.0 (the
  11  * "License"); you may not use this file except in compliance
  12  * with the License. You may obtain a copy of the License at
  13  *
  14  * http://www.apache.org/licenses/LICENSE-2.0
  15  *
  16  * Unless required by applicable law or agreed to in writing,
  17  * software distributed under the License is distributed on an
  18  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  19  * KIND, either express or implied. See the License for the
  20  * specific language governing permissions and limitations
  21  * under the License.
  22  */
  23 package com.sun.org.apache.xml.internal.security.encryption;
  24 
  25 import java.io.ByteArrayOutputStream;
  26 import java.io.IOException;
  27 import java.io.OutputStreamWriter;
  28 import java.io.UnsupportedEncodingException;
  29 import java.util.HashMap;
  30 import java.util.Map;
  31 
  32 import com.sun.org.apache.xml.internal.security.c14n.Canonicalizer;
  33 import org.w3c.dom.Element;
  34 import org.w3c.dom.NamedNodeMap;
  35 import org.w3c.dom.Node;
  36 import org.w3c.dom.NodeList;
  37 
  38 /**
  39  * Converts <code>String</code>s into <code>Node</code>s and visa versa.
  40  *
  41  * An abstract class for common Serializer functionality
  42  */
  43 public abstract class AbstractSerializer implements Serializer {
  44 
  45     protected Canonicalizer canon;
  46 
  47     public void setCanonicalizer(Canonicalizer canon) {
  48         this.canon = canon;
  49     }
  50 
  51     /**
  52      * Returns a <code>String</code> representation of the specified
  53      * <code>Element</code>.
  54      * <p/>
  55      * Refer also to comments about setup of format.
  56      *
  57      * @param element the <code>Element</code> to serialize.
  58      * @return the <code>String</code> representation of the serilaized
  59      *   <code>Element</code>.
  60      * @throws Exception
  61      */
  62     public String serialize(Element element) throws Exception {
  63         return canonSerialize(element);
  64     }
  65 
  66     /**
  67      * Returns a <code>byte[]</code> representation of the specified
  68      * <code>Element</code>.
  69      *
  70      * @param element the <code>Element</code> to serialize.
  71      * @return the <code>byte[]</code> representation of the serilaized
  72      *   <code>Element</code>.
  73      * @throws Exception
  74      */
  75     public byte[] serializeToByteArray(Element element) throws Exception {
  76         return canonSerializeToByteArray(element);
  77     }
  78 
  79     /**
  80      * Returns a <code>String</code> representation of the specified
  81      * <code>NodeList</code>.
  82      * <p/>
  83      * This is a special case because the NodeList may represent a
  84      * <code>DocumentFragment</code>. A document fragment may be a
  85      * non-valid XML document (refer to appropriate description of
  86      * W3C) because it my start with a non-element node, e.g. a text
  87      * node.
  88      * <p/>
  89      * The methods first converts the node list into a document fragment.
  90      * Special care is taken to not destroy the current document, thus
  91      * the method clones the nodes (deep cloning) before it appends
  92      * them to the document fragment.
  93      * <p/>
  94      * Refer also to comments about setup of format.
  95      *
  96      * @param content the <code>NodeList</code> to serialize.
  97      * @return the <code>String</code> representation of the serialized
  98      *   <code>NodeList</code>.
  99      * @throws Exception
 100      */
 101     public String serialize(NodeList content) throws Exception {
 102         ByteArrayOutputStream baos = new ByteArrayOutputStream();
 103         canon.setWriter(baos);
 104         canon.notReset();
 105         for (int i = 0; i < content.getLength(); i++) {
 106             canon.canonicalizeSubtree(content.item(i));
 107         }
 108         String ret = baos.toString("UTF-8");
 109         baos.reset();
 110         return ret;
 111     }
 112 
 113     /**
 114      * Returns a <code>byte[]</code> representation of the specified
 115      * <code>NodeList</code>.
 116      *
 117      * @param content the <code>NodeList</code> to serialize.
 118      * @return the <code>byte[]</code> representation of the serialized
 119      *   <code>NodeList</code>.
 120      * @throws Exception
 121      */
 122     public byte[] serializeToByteArray(NodeList content) throws Exception {
 123         ByteArrayOutputStream baos = new ByteArrayOutputStream();
 124         canon.setWriter(baos);
 125         canon.notReset();
 126         for (int i = 0; i < content.getLength(); i++) {
 127             canon.canonicalizeSubtree(content.item(i));
 128         }
 129         return baos.toByteArray();
 130     }
 131 
 132     /**
 133      * Use the Canonicalizer to serialize the node
 134      * @param node
 135      * @return the canonicalization of the node
 136      * @throws Exception
 137      */
 138     public String canonSerialize(Node node) throws Exception {
 139         ByteArrayOutputStream baos = new ByteArrayOutputStream();
 140         canon.setWriter(baos);
 141         canon.notReset();
 142         canon.canonicalizeSubtree(node);
 143         String ret = baos.toString("UTF-8");
 144         baos.reset();
 145         return ret;
 146     }
 147 
 148     /**
 149      * Use the Canonicalizer to serialize the node
 150      * @param node
 151      * @return the (byte[]) canonicalization of the node
 152      * @throws Exception
 153      */
 154     public byte[] canonSerializeToByteArray(Node node) throws Exception {
 155         ByteArrayOutputStream baos = new ByteArrayOutputStream();
 156         canon.setWriter(baos);
 157         canon.notReset();
 158         canon.canonicalizeSubtree(node);
 159         return baos.toByteArray();
 160     }
 161 
 162     /**
 163      * @param source
 164      * @param ctx
 165      * @return the Node resulting from the parse of the source
 166      * @throws XMLEncryptionException
 167      */
 168     public abstract Node deserialize(String source, Node ctx) throws XMLEncryptionException;
 169 
 170     /**
 171      * @param source
 172      * @param ctx
 173      * @return the Node resulting from the parse of the source
 174      * @throws XMLEncryptionException
 175      */
 176     public abstract Node deserialize(byte[] source, Node ctx) throws XMLEncryptionException;
 177 
 178     protected static byte[] createContext(byte[] source, Node ctx) throws XMLEncryptionException {
 179         // Create the context to parse the document against
 180         ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
 181         try {
 182             OutputStreamWriter outputStreamWriter = new OutputStreamWriter(byteArrayOutputStream, "UTF-8");
 183             outputStreamWriter.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?><dummy");
 184 
 185             // Run through each node up to the document node and find any xmlns: nodes
 186             Map<String, String> storedNamespaces = new HashMap<String, String>();
 187             Node wk = ctx;
 188             while (wk != null) {
 189                 NamedNodeMap atts = wk.getAttributes();
 190                 if (atts != null) {
 191                     for (int i = 0; i < atts.getLength(); ++i) {
 192                         Node att = atts.item(i);
 193                         String nodeName = att.getNodeName();
 194                         if ((nodeName.equals("xmlns") || nodeName.startsWith("xmlns:"))
 195                                 && !storedNamespaces.containsKey(att.getNodeName())) {
 196                             outputStreamWriter.write(" ");
 197                             outputStreamWriter.write(nodeName);
 198                             outputStreamWriter.write("=\"");
 199                             outputStreamWriter.write(att.getNodeValue());
 200                             outputStreamWriter.write("\"");
 201                             storedNamespaces.put(nodeName, att.getNodeValue());
 202                         }
 203                     }
 204                 }
 205                 wk = wk.getParentNode();
 206             }
 207             outputStreamWriter.write(">");
 208             outputStreamWriter.flush();
 209             byteArrayOutputStream.write(source);
 210 
 211             outputStreamWriter.write("</dummy>");
 212             outputStreamWriter.close();
 213 
 214             return byteArrayOutputStream.toByteArray();
 215         } catch (UnsupportedEncodingException e) {
 216             throw new XMLEncryptionException("empty", e);
 217         } catch (IOException e) {
 218             throw new XMLEncryptionException("empty", e);
 219         }
 220     }
 221 
 222     protected static String createContext(String source, Node ctx) {
 223         // Create the context to parse the document against
 224         StringBuilder sb = new StringBuilder();
 225         sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?><dummy");
 226 
 227         // Run through each node up to the document node and find any xmlns: nodes
 228         Map<String, String> storedNamespaces = new HashMap<String, String>();
 229         Node wk = ctx;
 230         while (wk != null) {
 231             NamedNodeMap atts = wk.getAttributes();
 232             if (atts != null) {
 233                 for (int i = 0; i < atts.getLength(); ++i) {
 234                     Node att = atts.item(i);
 235                     String nodeName = att.getNodeName();
 236                     if ((nodeName.equals("xmlns") || nodeName.startsWith("xmlns:"))
 237                         && !storedNamespaces.containsKey(att.getNodeName())) {
 238                         sb.append(' ').append(nodeName).append("=\"")
 239                                 .append(att.getNodeValue()).append('"');
 240                         storedNamespaces.put(nodeName, att.getNodeValue());
 241                     }
 242                 }
 243             }
 244             wk = wk.getParentNode();
 245         }
 246         sb.append('>').append(source).append("</dummy>");
 247         return sb.toString();
 248     }
 249 
 250 }