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
45
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 }