001 package org.apache.commons.ssl.asn1;
002
003 import java.io.ByteArrayOutputStream;
004 import java.io.IOException;
005
006 public class DERBitString
007 extends ASN1Object
008 implements DERString {
009 private static final char[] table = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
010
011 protected byte[] data;
012 protected int padBits;
013
014 /**
015 * return the correct number of pad bits for a bit string defined in
016 * a 32 bit constant
017 */
018 static protected int getPadBits(
019 int bitString) {
020 int val = 0;
021 for (int i = 3; i >= 0; i--) {
022 //
023 // this may look a little odd, but if it isn't done like this pre jdk1.2
024 // JVM's break!
025 //
026 if (i != 0) {
027 if ((bitString >> (i * 8)) != 0) {
028 val = (bitString >> (i * 8)) & 0xFF;
029 break;
030 }
031 } else {
032 if (bitString != 0) {
033 val = bitString & 0xFF;
034 break;
035 }
036 }
037 }
038
039 if (val == 0) {
040 return 7;
041 }
042
043
044 int bits = 1;
045
046 while (((val <<= 1) & 0xFF) != 0) {
047 bits++;
048 }
049
050 return 8 - bits;
051 }
052
053 /**
054 * return the correct number of bytes for a bit string defined in
055 * a 32 bit constant
056 */
057 static protected byte[] getBytes(int bitString) {
058 int bytes = 4;
059 for (int i = 3; i >= 1; i--) {
060 if ((bitString & (0xFF << (i * 8))) != 0) {
061 break;
062 }
063 bytes--;
064 }
065
066 byte[] result = new byte[bytes];
067 for (int i = 0; i < bytes; i++) {
068 result[i] = (byte) ((bitString >> (i * 8)) & 0xFF);
069 }
070
071 return result;
072 }
073
074 /**
075 * return a Bit String from the passed in object
076 *
077 * @throws IllegalArgumentException if the object cannot be converted.
078 */
079 public static DERBitString getInstance(
080 Object obj) {
081 if (obj == null || obj instanceof DERBitString) {
082 return (DERBitString) obj;
083 }
084
085 if (obj instanceof ASN1OctetString) {
086 byte[] bytes = ((ASN1OctetString) obj).getOctets();
087 int padBits = bytes[0];
088 byte[] data = new byte[bytes.length - 1];
089
090 System.arraycopy(bytes, 1, data, 0, bytes.length - 1);
091
092 return new DERBitString(data, padBits);
093 }
094
095 if (obj instanceof ASN1TaggedObject) {
096 return getInstance(((ASN1TaggedObject) obj).getObject());
097 }
098
099 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 * @throws IllegalArgumentException if the tagged object cannot
109 * be converted.
110 */
111 public static DERBitString getInstance(
112 ASN1TaggedObject obj,
113 boolean explicit) {
114 return getInstance(obj.getObject());
115 }
116
117 protected DERBitString(
118 byte data,
119 int padBits) {
120 this.data = new byte[1];
121 this.data[0] = data;
122 this.padBits = padBits;
123 }
124
125 /**
126 * @param data the octets making up the bit string.
127 * @param padBits the number of extra bits at the end of the string.
128 */
129 public DERBitString(
130 byte[] data,
131 int padBits) {
132 this.data = data;
133 this.padBits = padBits;
134 }
135
136 public DERBitString(
137 byte[] data) {
138 this(data, 0);
139 }
140
141 public DERBitString(
142 DEREncodable obj) {
143 try {
144 ByteArrayOutputStream bOut = new ByteArrayOutputStream();
145 DEROutputStream dOut = new DEROutputStream(bOut);
146
147 dOut.writeObject(obj);
148 dOut.close();
149
150 this.data = bOut.toByteArray();
151 this.padBits = 0;
152 }
153 catch (IOException e) {
154 throw new IllegalArgumentException("Error processing object : " + e.toString());
155 }
156 }
157
158 public byte[] getBytes() {
159 return data;
160 }
161
162 public int getPadBits() {
163 return padBits;
164 }
165
166
167 /** @return the value of the bit string as an int (truncating if necessary) */
168 public int intValue() {
169 int value = 0;
170
171 for (int i = 0; i != data.length && i != 4; i++) {
172 value |= (data[i] & 0xff) << (8 * i);
173 }
174
175 return value;
176 }
177
178 void encode(
179 DEROutputStream out)
180 throws IOException {
181 byte[] bytes = new byte[getBytes().length + 1];
182
183 bytes[0] = (byte) getPadBits();
184 System.arraycopy(getBytes(), 0, bytes, 1, bytes.length - 1);
185
186 out.writeEncoded(BIT_STRING, bytes);
187 }
188
189 public int hashCode() {
190 int value = 0;
191
192 for (int i = 0; i != data.length; i++) {
193 value ^= (data[i] & 0xff) << (i % 4);
194 }
195
196 return value;
197 }
198
199 protected boolean asn1Equals(
200 DERObject o) {
201 if (!(o instanceof DERBitString)) {
202 return false;
203 }
204
205 DERBitString other = (DERBitString) o;
206
207 if (data.length != other.data.length) {
208 return false;
209 }
210
211 for (int i = 0; i != data.length; i++) {
212 if (data[i] != other.data[i]) {
213 return false;
214 }
215 }
216
217 return (padBits == other.padBits);
218 }
219
220 public String getString() {
221 StringBuffer buf = new StringBuffer("#");
222 ByteArrayOutputStream bOut = new ByteArrayOutputStream();
223 ASN1OutputStream aOut = new ASN1OutputStream(bOut);
224
225 try {
226 aOut.writeObject(this);
227 }
228 catch (IOException e) {
229 throw new RuntimeException("internal error encoding BitString");
230 }
231
232 byte[] string = bOut.toByteArray();
233
234 for (int i = 0; i != string.length; i++) {
235 buf.append(table[(string[i] >>> 4) & 0xf]);
236 buf.append(table[string[i] & 0xf]);
237 }
238
239 return buf.toString();
240 }
241
242 public String toString() {
243 return getString();
244 }
245 }