Home | History | Annotate | Download | only in asn1
      1 package org.bouncycastle.asn1;
      2 
      3 import java.io.ByteArrayOutputStream;
      4 import java.io.IOException;
      5 
      6 import org.bouncycastle.util.Arrays;
      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         throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
    104     }
    105 
    106     /**
    107      * return a Bit String from a tagged object.
    108      *
    109      * @param obj the tagged object holding the object we want
    110      * @param explicit true if the object is meant to be explicitly
    111      *              tagged false otherwise.
    112      * @exception IllegalArgumentException if the tagged object cannot
    113      *               be converted.
    114      */
    115     public static DERBitString getInstance(
    116         ASN1TaggedObject obj,
    117         boolean          explicit)
    118     {
    119         DERObject o = obj.getObject();
    120 
    121         if (explicit || o instanceof DERBitString)
    122         {
    123             return getInstance(o);
    124         }
    125         else
    126         {
    127             return fromOctetString(((ASN1OctetString)o).getOctets());
    128         }
    129     }
    130 
    131     protected DERBitString(
    132         byte    data,
    133         int     padBits)
    134     {
    135         this.data = new byte[1];
    136         this.data[0] = data;
    137         this.padBits = padBits;
    138     }
    139 
    140     /**
    141      * @param data the octets making up the bit string.
    142      * @param padBits the number of extra bits at the end of the string.
    143      */
    144     public DERBitString(
    145         byte[]  data,
    146         int     padBits)
    147     {
    148         this.data = data;
    149         this.padBits = padBits;
    150     }
    151 
    152     public DERBitString(
    153         byte[]  data)
    154     {
    155         this(data, 0);
    156     }
    157 
    158     public DERBitString(
    159         DEREncodable  obj)
    160     {
    161         try
    162         {
    163             this.data = obj.getDERObject().getEncoded(ASN1Encodable.DER);
    164             this.padBits = 0;
    165         }
    166         catch (IOException e)
    167         {
    168             throw new IllegalArgumentException("Error processing object : " + e.toString());
    169         }
    170     }
    171 
    172     public byte[] getBytes()
    173     {
    174         return data;
    175     }
    176 
    177     public int getPadBits()
    178     {
    179         return padBits;
    180     }
    181 
    182 
    183     /**
    184      * @return the value of the bit string as an int (truncating if necessary)
    185      */
    186     public int intValue()
    187     {
    188         int value = 0;
    189 
    190         for (int i = 0; i != data.length && i != 4; i++)
    191         {
    192             value |= (data[i] & 0xff) << (8 * i);
    193         }
    194 
    195         return value;
    196     }
    197 
    198     void encode(
    199         DEROutputStream  out)
    200         throws IOException
    201     {
    202         byte[]  bytes = new byte[getBytes().length + 1];
    203 
    204         bytes[0] = (byte)getPadBits();
    205         System.arraycopy(getBytes(), 0, bytes, 1, bytes.length - 1);
    206 
    207         out.writeEncoded(BIT_STRING, bytes);
    208     }
    209 
    210     public int hashCode()
    211     {
    212         return padBits ^ Arrays.hashCode(data);
    213     }
    214 
    215     protected boolean asn1Equals(
    216         DERObject  o)
    217     {
    218         if (!(o instanceof DERBitString))
    219         {
    220             return false;
    221         }
    222 
    223         DERBitString other = (DERBitString)o;
    224 
    225         return this.padBits == other.padBits
    226             && Arrays.areEqual(this.data, other.data);
    227     }
    228 
    229     public String getString()
    230     {
    231         StringBuffer          buf = new StringBuffer("#");
    232         ByteArrayOutputStream bOut = new ByteArrayOutputStream();
    233         ASN1OutputStream      aOut = new ASN1OutputStream(bOut);
    234 
    235         try
    236         {
    237             aOut.writeObject(this);
    238         }
    239         catch (IOException e)
    240         {
    241            throw new RuntimeException("internal error encoding BitString");
    242         }
    243 
    244         byte[]    string = bOut.toByteArray();
    245 
    246         for (int i = 0; i != string.length; i++)
    247         {
    248             buf.append(table[(string[i] >>> 4) & 0xf]);
    249             buf.append(table[string[i] & 0xf]);
    250         }
    251 
    252         return buf.toString();
    253     }
    254 
    255     public String toString()
    256     {
    257         return getString();
    258     }
    259 
    260     static DERBitString fromOctetString(byte[] bytes)
    261     {
    262         if (bytes.length < 1)
    263         {
    264             throw new IllegalArgumentException("truncated BIT STRING detected");
    265         }
    266 
    267         int padBits = bytes[0];
    268         byte[] data = new byte[bytes.length - 1];
    269 
    270         if (data.length != 0)
    271         {
    272             System.arraycopy(bytes, 1, data, 0, bytes.length - 1);
    273         }
    274 
    275         return new DERBitString(data, padBits);
    276     }
    277 }
    278