View Javadoc

1   /**
2    *
3    *  Licensed to the Apache Software Foundation (ASF) under one or more
4    *  contributor license agreements.  See the NOTICE file distributed with
5    *  this work for additional information regarding copyright ownership.
6    *  The ASF licenses this file to You under the Apache License, Version 2.0
7    *  (the "License"); you may not use this file except in compliance with
8    *  the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing, software
13   *  distributed under the License is distributed on an "AS IS" BASIS,
14   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   *  See the License for the specific language governing permissions and
16   *  limitations under the License.
17   */
18  
19  package org.apache.geronimo.util.asn1;
20  
21  import java.io.ByteArrayOutputStream;
22  import java.io.IOException;
23  
24  public class DERBitString
25      extends DERObject
26      implements DERString
27  {
28      private static final char[]  table = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
29  
30      protected byte[]      data;
31      protected int         padBits;
32  
33      /**
34       * return the correct number of pad bits for a bit string defined in
35       * a 32 bit constant
36       */
37      static protected int getPadBits(
38          int bitString)
39      {
40          int val = 0;
41          for (int i = 3; i >= 0; i--)
42          {
43              //
44              // this may look a little odd, but if it isn't done like this pre jdk1.2
45              // JVM's break!
46              //
47              if (i != 0)
48              {
49                  if ((bitString >> (i * 8)) != 0)
50                  {
51                      val = (bitString >> (i * 8)) & 0xFF;
52                      break;
53                  }
54              }
55              else
56              {
57                  if (bitString != 0)
58                  {
59                      val = bitString & 0xFF;
60                      break;
61                  }
62              }
63          }
64  
65          if (val == 0)
66          {
67              return 7;
68          }
69  
70  
71          int bits = 1;
72  
73          while (((val <<= 1) & 0xFF) != 0)
74          {
75              bits++;
76          }
77  
78          return 8 - bits;
79      }
80  
81      /**
82       * return the correct number of bytes for a bit string defined in
83       * a 32 bit constant
84       */
85      static protected byte[] getBytes(int bitString)
86      {
87          int bytes = 4;
88          for (int i = 3; i >= 1; i--)
89          {
90              if ((bitString & (0xFF << (i * 8))) != 0)
91              {
92                  break;
93              }
94              bytes--;
95          }
96  
97          byte[] result = new byte[bytes];
98          for (int i = 0; i < bytes; i++)
99          {
100             result[i] = (byte) ((bitString >> (i * 8)) & 0xFF);
101         }
102 
103         return result;
104     }
105 
106     /**
107      * return a Bit String from the passed in object
108      *
109      * @exception IllegalArgumentException if the object cannot be converted.
110      */
111     public static DERBitString getInstance(
112         Object  obj)
113     {
114         if (obj == null || obj instanceof DERBitString)
115         {
116             return (DERBitString)obj;
117         }
118 
119         if (obj instanceof ASN1OctetString)
120         {
121             byte[]  bytes = ((ASN1OctetString)obj).getOctets();
122             int     padBits = bytes[0];
123             byte[]  data = new byte[bytes.length - 1];
124 
125             System.arraycopy(bytes, 1, data, 0, bytes.length - 1);
126 
127             return new DERBitString(data, padBits);
128         }
129 
130         if (obj instanceof ASN1TaggedObject)
131         {
132             return getInstance(((ASN1TaggedObject)obj).getObject());
133         }
134 
135         throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
136     }
137 
138     /**
139      * return a Bit String from a tagged object.
140      *
141      * @param obj the tagged object holding the object we want
142      * @param explicit true if the object is meant to be explicitly
143      *              tagged false otherwise.
144      * @exception IllegalArgumentException if the tagged object cannot
145      *               be converted.
146      */
147     public static DERBitString getInstance(
148         ASN1TaggedObject obj,
149         boolean          explicit)
150     {
151         return getInstance(obj.getObject());
152     }
153 
154     protected DERBitString(
155         byte    data,
156         int     padBits)
157     {
158         this.data = new byte[1];
159         this.data[0] = data;
160         this.padBits = padBits;
161     }
162 
163     /**
164      * @param data the octets making up the bit string.
165      * @param padBits the number of extra bits at the end of the string.
166      */
167     public DERBitString(
168         byte[]  data,
169         int     padBits)
170     {
171         this.data = data;
172         this.padBits = padBits;
173     }
174 
175     public DERBitString(
176         byte[]  data)
177     {
178         this(data, 0);
179     }
180 
181     public DERBitString(
182         DEREncodable  obj)
183     {
184         try
185         {
186             ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
187             DEROutputStream         dOut = new DEROutputStream(bOut);
188 
189             dOut.writeObject(obj);
190             dOut.close();
191 
192             this.data = bOut.toByteArray();
193             this.padBits = 0;
194         }
195         catch (IOException e)
196         {
197             throw new IllegalArgumentException("Error processing object : " + e.toString());
198         }
199     }
200 
201     public byte[] getBytes()
202     {
203         return data;
204     }
205 
206     public int getPadBits()
207     {
208         return padBits;
209     }
210 
211 
212     /**
213      * @return the value of the bit string as an int (truncating if necessary)
214      */
215     public int intValue()
216     {
217         int value = 0;
218 
219         for (int i = 0; i != data.length && i != 4; i++)
220         {
221             value |= (data[i] & 0xff) << (8 * i);
222         }
223 
224         return value;
225     }
226 
227     void encode(
228         DEROutputStream  out)
229         throws IOException
230     {
231         byte[]  bytes = new byte[getBytes().length + 1];
232 
233         bytes[0] = (byte)getPadBits();
234         System.arraycopy(getBytes(), 0, bytes, 1, bytes.length - 1);
235 
236         out.writeEncoded(BIT_STRING, bytes);
237     }
238 
239     public int hashCode()
240     {
241         int     value = 0;
242 
243         for (int i = 0; i != data.length; i++)
244         {
245             value ^= (data[i] & 0xff) << (i % 4);
246         }
247 
248         return value;
249     }
250 
251     public boolean equals(
252         Object  o)
253     {
254         if (o == null || !(o instanceof DERBitString))
255         {
256             return false;
257         }
258 
259         DERBitString  other = (DERBitString)o;
260 
261         if (data.length != other.data.length)
262         {
263             return false;
264         }
265 
266         for (int i = 0; i != data.length; i++)
267         {
268             if (data[i] != other.data[i])
269             {
270                 return false;
271             }
272         }
273 
274         return (padBits == other.padBits);
275     }
276 
277     public String getString()
278     {
279         StringBuffer          buf = new StringBuffer("#");
280         ByteArrayOutputStream bOut = new ByteArrayOutputStream();
281         ASN1OutputStream      aOut = new ASN1OutputStream(bOut);
282 
283         try
284         {
285             aOut.writeObject(this);
286         }
287         catch (IOException e)
288         {
289            throw new RuntimeException("internal error encoding BitString");
290         }
291 
292         byte[]    string = bOut.toByteArray();
293 
294         for (int i = 0; i != string.length; i++)
295         {
296             buf.append(table[(string[i] >>> 4) % 0xf]);
297             buf.append(table[string[i] & 0xf]);
298         }
299 
300         return buf.toString();
301     }
302 }