Home | History | Annotate | Download | only in pem
      1 package org.bouncycastle.util.io.pem;
      2 
      3 import java.io.BufferedWriter;
      4 import java.io.IOException;
      5 import java.io.Writer;
      6 import java.util.Iterator;
      7 
      8 import org.bouncycastle.util.encoders.Base64;
      9 
     10 /**
     11  * A generic PEM writer, based on RFC 1421
     12  */
     13 public class PemWriter
     14     extends BufferedWriter
     15 {
     16     private static final int LINE_LENGTH = 64;
     17 
     18     private final int nlLength;
     19     private char[]  buf = new char[LINE_LENGTH];
     20 
     21     /**
     22      * Base constructor.
     23      *
     24      * @param out output stream to use.
     25      */
     26     public PemWriter(Writer out)
     27     {
     28         super(out);
     29 
     30         String nl = System.getProperty("line.separator");
     31         if (nl != null)
     32         {
     33             nlLength = nl.length();
     34         }
     35         else
     36         {
     37             nlLength = 2;
     38         }
     39     }
     40 
     41     /**
     42      * Return the number of bytes or characters required to contain the
     43      * passed in object if it is PEM encoded.
     44      *
     45      * @param obj pem object to be output
     46      * @return an estimate of the number of bytes
     47      */
     48     public int getOutputSize(PemObject obj)
     49     {
     50         // BEGIN and END boundaries.
     51         int size = (2 * (obj.getType().length() + 10 + nlLength)) + 6 + 4;
     52 
     53         if (!obj.getHeaders().isEmpty())
     54         {
     55             for (Iterator it = obj.getHeaders().iterator(); it.hasNext();)
     56             {
     57                 PemHeader hdr = (PemHeader)it.next();
     58 
     59                 size += hdr.getName().length() + ": ".length() + hdr.getValue().length() + nlLength;
     60             }
     61 
     62             size += nlLength;
     63         }
     64 
     65         // base64 encoding
     66         int dataLen = ((obj.getContent().length + 2) / 3) * 4;
     67 
     68         size += dataLen + (((dataLen + LINE_LENGTH - 1) / LINE_LENGTH) * nlLength);
     69 
     70         return size;
     71     }
     72 
     73     public void writeObject(PemObjectGenerator objGen)
     74         throws IOException
     75     {
     76         PemObject obj = objGen.generate();
     77 
     78         writePreEncapsulationBoundary(obj.getType());
     79 
     80         if (!obj.getHeaders().isEmpty())
     81         {
     82             for (Iterator it = obj.getHeaders().iterator(); it.hasNext();)
     83             {
     84                 PemHeader hdr = (PemHeader)it.next();
     85 
     86                 this.write(hdr.getName());
     87                 this.write(": ");
     88                 this.write(hdr.getValue());
     89                 this.newLine();
     90             }
     91 
     92             this.newLine();
     93         }
     94 
     95         writeEncoded(obj.getContent());
     96         writePostEncapsulationBoundary(obj.getType());
     97     }
     98 
     99     private void writeEncoded(byte[] bytes)
    100         throws IOException
    101     {
    102         bytes = Base64.encode(bytes);
    103 
    104         for (int i = 0; i < bytes.length; i += buf.length)
    105         {
    106             int index = 0;
    107 
    108             while (index != buf.length)
    109             {
    110                 if ((i + index) >= bytes.length)
    111                 {
    112                     break;
    113                 }
    114                 buf[index] = (char)bytes[i + index];
    115                 index++;
    116             }
    117             this.write(buf, 0, index);
    118             this.newLine();
    119         }
    120     }
    121 
    122     private void writePreEncapsulationBoundary(
    123         String type)
    124         throws IOException
    125     {
    126         this.write("-----BEGIN " + type + "-----");
    127         this.newLine();
    128     }
    129 
    130     private void writePostEncapsulationBoundary(
    131         String type)
    132         throws IOException
    133     {
    134         this.write("-----END " + type + "-----");
    135         this.newLine();
    136     }
    137 }
    138