Home | History | Annotate | Download | only in asn1
      1 package org.bouncycastle.asn1;
      2 
      3 import org.bouncycastle.util.Arrays;
      4 
      5 import java.io.ByteArrayOutputStream;
      6 import java.io.IOException;
      7 
      8 public class DERBitString
      9     extends ASN1Object
     10     implements DERString
     11 {
     12     private static final char[]  table = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
     13 
     14     protected byte[]      data;
     15     protected int         padBits;
     16 
     17     /**
     18      * return the correct number of pad bits for a bit string defined in
     19      * a 32 bit constant
     20      */
     21     static protected int getPadBits(
     22         int bitString)
     23     {
     24         int val = 0;
     25         for (int i = 3; i >= 0; i--)
     26         {
     27             //
     28             // this may look a little odd, but if it isn't done like this pre jdk1.2
     29             // JVM's break!
     30             //
     31             if (i != 0)
     32             {
     33                 if ((bitString >> (i * 8)) != 0)
     34                 {
     35                     val = (bitString >> (i * 8)) & 0xFF;
     36                     break;
     37                 }
     38             }
     39             else
     40             {
     41                 if (bitString != 0)
     42                 {
     43                     val = bitString & 0xFF;
     44                     break;
     45                 }
     46             }
     47         }
     48 
     49         if (val == 0)
     50         {
     51             return 7;
     52         }
     53 
     54 
     55         int bits = 1;
     56 
     57         while (((val <<= 1) & 0xFF) != 0)
     58         {
     59             bits++;
     60         }
     61 
     62         return 8 - bits;
     63     }
     64 
     65     /**
     66      * return the correct number of bytes for a bit string defined in
     67      * a 32 bit constant
     68      */
     69     static protected byte[] getBytes(int bitString)
     70     {
     71         int bytes = 4;
     72         for (int i = 3; i >= 1; i--)
     73         {
     74             if ((bitString & (0xFF << (i * 8))) != 0)
     75             {
     76                 break;
     77             }
     78             bytes--;
     79         }
     80 
     81         byte[] result = new byte[bytes];
     82         for (int i = 0; i < bytes; i++)
     83         {
     84             result[i] = (byte) ((bitString >> (i * 8)) & 0xFF);
     85         }
     86 
     87         return result;
     88     }
     89 
     90     /**
     91      * return a Bit String from the passed in object
     92      *
     93      * @exception IllegalArgumentException if the object cannot be converted.
     94      */
     95     public static DERBitString getInstance(
     96         Object  obj)
     97     {
     98         if (obj == null || obj instanceof DERBitString)
     99         {
    100             return (DERBitString)obj;
    101         }
    102 
    103         if (obj instanceof ASN1OctetString)
    104         {
    105             byte[]  bytes = ((ASN1OctetString)obj).getOctets();
    106             int     padBits = bytes[0];
    107             byte[]  data = new byte[bytes.length - 1];
    108 
    109             System.arraycopy(bytes, 1, data, 0, bytes.length - 1);
    110 
    111             return new DERBitString(data, padBits);
    112         }
    113 
    114         if (obj instanceof ASN1TaggedObject)
    115         {
    116             return getInstance(((ASN1TaggedObject)obj).getObject());
    117         }
    118 
    119         throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
    120     }
    121 
    122     /**
    123      * return a Bit String from a tagged object.
    124      *
    125      * @param obj the tagged object holding the object we want
    126      * @param explicit true if the object is meant to be explicitly
    127      *              tagged false otherwise.
    128      * @exception IllegalArgumentException if the tagged object cannot
    129      *               be converted.
    130      */
    131     public static DERBitString getInstance(
    132         ASN1TaggedObject obj,
    133         boolean          explicit)
    134     {
    135         return getInstance(obj.getObject());
    136     }
    137 
    138     protected DERBitString(
    139         byte    data,
    140         int     padBits)
    141     {
    142         this.data = new byte[1];
    143         this.data[0] = data;
    144         this.padBits = padBits;
    145     }
    146 
    147     /**
    148      * @param data the octets making up the bit string.
    149      * @param padBits the number of extra bits at the end of the string.
    150      */
    151     public DERBitString(
    152         byte[]  data,
    153         int     padBits)
    154     {
    155         this.data = data;
    156         this.padBits = padBits;
    157     }
    158 
    159     public DERBitString(
    160         byte[]  data)
    161     {
    162         this(data, 0);
    163     }
    164 
    165     public DERBitString(
    166         DEREncodable  obj)
    167     {
    168         try
    169         {
    170             this.data = obj.getDERObject().getEncoded(ASN1Encodable.DER);
    171             this.padBits = 0;
    172         }
    173         catch (IOException e)
    174         {
    175             throw new IllegalArgumentException("Error processing object : " + e.toString());
    176         }
    177     }
    178 
    179     public byte[] getBytes()
    180     {
    181         return data;
    182     }
    183 
    184     public int getPadBits()
    185     {
    186         return padBits;
    187     }
    188 
    189 
    190     /**
    191      * @return the value of the bit string as an int (truncating if necessary)
    192      */
    193     public int intValue()
    194     {
    195         int value = 0;
    196 
    197         for (int i = 0; i != data.length && i != 4; i++)
    198         {
    199             value |= (data[i] & 0xff) << (8 * i);
    200         }
    201 
    202         return value;
    203     }
    204 
    205     void encode(
    206         DEROutputStream  out)
    207         throws IOException
    208     {
    209         byte[]  bytes = new byte[getBytes().length + 1];
    210 
    211         bytes[0] = (byte)getPadBits();
    212         System.arraycopy(getBytes(), 0, bytes, 1, bytes.length - 1);
    213 
    214         out.writeEncoded(BIT_STRING, bytes);
    215     }
    216 
    217     public int hashCode()
    218     {
    219         return padBits ^ Arrays.hashCode(data);
    220     }
    221 
    222     protected boolean asn1Equals(
    223         DERObject  o)
    224     {
    225         if (!(o instanceof DERBitString))
    226         {
    227             return false;
    228         }
    229 
    230         DERBitString other = (DERBitString)o;
    231 
    232         return this.padBits == other.padBits
    233             && Arrays.areEqual(this.data, other.data);
    234     }
    235 
    236     public String getString()
    237     {
    238         StringBuffer          buf = new StringBuffer("#");
    239         ByteArrayOutputStream bOut = new ByteArrayOutputStream();
    240         ASN1OutputStream      aOut = new ASN1OutputStream(bOut);
    241 
    242         try
    243         {
    244             aOut.writeObject(this);
    245         }
    246         catch (IOException e)
    247         {
    248            throw new RuntimeException("internal error encoding BitString");
    249         }
    250 
    251         byte[]    string = bOut.toByteArray();
    252 
    253         for (int i = 0; i != string.length; i++)
    254         {
    255             buf.append(table[(string[i] >>> 4) & 0xf]);
    256             buf.append(table[string[i] & 0xf]);
    257         }
    258 
    259         return buf.toString();
    260     }
    261 
    262     public String toString()
    263     {
    264         return getString();
    265     }
    266 }
    267