1    package org.bouncycastle.asn1;
2    
3    import java.io.*;
4    
5    public class DERBitString
6        extends DERObject
7    {
8        protected byte[]      data;
9        protected int         padBits;
10   
11       /**
12        * return the correct number of pad bits for a bit string defined in
13        * a 16 bit constant
14        */
15       static protected int getPadBits(
16           int bitString)
17       {
18           int val;
19   
20           if (bitString == 0)
21           {
22               return 7;
23           }
24   
25           if (bitString > 255)
26           {
27               val = ((bitString >> 8) & 0xFF);
28           }
29           else
30           {
31               val = (bitString & 0xFF);
32           }
33   
34           int bits = 1;
35   
36           while (((val <<= 1) & 0xFF) != 0)
37           {
38               bits++;
39           }
40   
41           return 8 - bits;
42       }
43   
44       /**
45        * return the correct number of bytes for a bit string defined in
46        * a 16 bit constant
47        */
48       static protected byte[] getBytes(
49           int bitString)
50       {
51           if (bitString > 255)
52           {
53               byte[]  bytes = new byte[2];
54   
55               bytes[0] = (byte)(bitString & 0xFF);
56               bytes[1] = (byte)((bitString >> 8) & 0xFF);
57   
58               return bytes;
59           }
60           else
61           {
62               byte[]  bytes = new byte[1];
63   
64               bytes[0] = (byte)(bitString & 0xFF);
65   
66               return bytes;
67           }
68       }
69   
70       /**
71        * return a Bit String from the passed in object
72        *
73        * @exception IllegalArgumentException if the object cannot be converted.
74        */
75       public static DERBitString getInstance(
76           Object  obj)
77       {
78           if (obj == null || obj instanceof DERBitString)
79           {
80               return (DERBitString)obj;
81           }
82   
83           if (obj instanceof ASN1OctetString)
84           {
85               byte[]  bytes = ((ASN1OctetString)obj).getOctets();
86               int     padBits = bytes[0];
87               byte[]  data = new byte[bytes.length - 1];
88   
89               System.arraycopy(bytes, 1, data, 0, bytes.length - 1);
90   
91               return new DERBitString(data, padBits);
92           }
93   
94           if (obj instanceof ASN1TaggedObject)
95           {
96               return getInstance(((ASN1TaggedObject)obj).getObject());
97           }
98   
99           throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
100      }
101  
102      /**
103       * return a Bit String from a tagged object.
104       *
105       * @param obj the tagged object holding the object we want
106       * @param explicit true if the object is meant to be explicitly
107       *              tagged false otherwise.
108       * @exception IllegalArgumentException if the tagged object cannot
109       *               be converted.
110       */
111      public static DERBitString getInstance(
112          ASN1TaggedObject obj,
113          boolean          explicit)
114      {
115          return getInstance(obj.getObject());
116      }
117      
118      protected DERBitString(
119          byte    data,
120          int     padBits)
121      {
122          this.data = new byte[1];
123          this.data[0] = data;
124          this.padBits = padBits;
125      }
126  
127      /**
128       * @param data the octets making up the bit string.
129       * @param padBits the number of extra bits at the end of the string.
130       */
131      public DERBitString(
132          byte[]  data,
133          int     padBits)
134      {
135          this.data = data;
136          this.padBits = padBits;
137      }
138  
139      public DERBitString(
140          byte[]  data)
141      {
142          this(data, 0);
143      }
144  
145      public DERBitString(
146          DEREncodable  obj)
147      {
148          try
149          {
150              ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
151              DEROutputStream         dOut = new DEROutputStream(bOut);
152  
153              dOut.writeObject(obj);
154              dOut.close();
155  
156              this.data = bOut.toByteArray();
157              this.padBits = 0;
158          }
159          catch (IOException e)
160          {
161              throw new IllegalArgumentException("Error processing object : " + e.toString());
162          }
163      }
164  
165      public byte[] getBytes()
166      {
167          return data;
168      }
169  
170      public int getPadBits()
171      {
172          return padBits;
173      }
174  
175      void encode(
176          DEROutputStream  out)
177          throws IOException
178      {
179          byte[]  bytes = new byte[getBytes().length + 1];
180  
181          bytes[0] = (byte)getPadBits();
182          System.arraycopy(getBytes(), 0, bytes, 1, bytes.length - 1);
183  
184          out.writeEncoded(BIT_STRING, bytes);
185      }
186      
187      public boolean equals(
188          Object  o)
189      {
190          if (o == null || !(o instanceof DERBitString))
191          {
192              return false;
193          }
194  
195          DERBitString  other = (DERBitString)o;
196  
197          if (data.length != other.data.length)
198          {
199              return false;
200          }
201  
202          for (int i = 0; i != data.length; i++)
203          {
204              if (data[i] != other.data[i])
205              {
206                  return false;
207              }
208          }
209  
210          return (padBits == other.padBits);
211      }
212  }
213