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