package org.bouncycastle.asn1; import java.io.IOException; /** * A BIT STRING with DER encoding - the first byte contains the count of padding bits included in the byte array's last byte. */ public class DERBitString extends ASN1BitString { /** * return a Bit String from the passed in object * * @param obj a DERBitString or an object that can be converted into one. * @exception IllegalArgumentException if the object cannot be converted. * @return a DERBitString instance, or null. */ public static DERBitString getInstance( Object obj) { if (obj == null || obj instanceof DERBitString) { return (DERBitString)obj; } if (obj instanceof DLBitString) { return new DERBitString(((DLBitString)obj).data, ((DLBitString)obj).padBits); } if (obj instanceof byte[]) { try { return (DERBitString)fromByteArray((byte[])obj); } catch (Exception e) { throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); } } throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); } /** * return a Bit String from a tagged object. * * @param obj the tagged object holding the object we want * @param explicit true if the object is meant to be explicitly * tagged false otherwise. * @exception IllegalArgumentException if the tagged object cannot * be converted. * @return a DERBitString instance, or null. */ public static DERBitString getInstance( ASN1TaggedObject obj, boolean explicit) { ASN1Primitive o = obj.getObject(); if (explicit || o instanceof DERBitString) { return getInstance(o); } else { return fromOctetString(ASN1OctetString.getInstance(o).getOctets()); } } protected DERBitString(byte data, int padBits) { super(data, padBits); } /** * @param data the octets making up the bit string. * @param padBits the number of extra bits at the end of the string. */ public DERBitString( byte[] data, int padBits) { super(data, padBits); } public DERBitString( byte[] data) { this(data, 0); } public DERBitString( int value) { super(getBytes(value), getPadBits(value)); } public DERBitString( ASN1Encodable obj) throws IOException { super(obj.toASN1Primitive().getEncoded(ASN1Encoding.DER), 0); } boolean isConstructed() { return false; } int encodedLength() { return 1 + StreamUtil.calculateBodyLength(data.length + 1) + data.length + 1; } void encode(ASN1OutputStream out, boolean withTag) throws IOException { int len = data.length; if (0 == len || 0 == padBits || (data[len - 1] == (byte)(data[len - 1] & (0xFF << padBits)))) { out.writeEncoded(withTag, BERTags.BIT_STRING, (byte)padBits, data); } else { byte der = (byte)(data[len - 1] & (0xFF << padBits)); out.writeEncoded(withTag, BERTags.BIT_STRING, (byte)padBits, data, 0, len - 1, der); } } ASN1Primitive toDERObject() { return this; } ASN1Primitive toDLObject() { return this; } static DERBitString fromOctetString(byte[] bytes) { if (bytes.length < 1) { throw new IllegalArgumentException("truncated BIT STRING detected"); } int padBits = bytes[0]; byte[] data = new byte[bytes.length - 1]; if (data.length != 0) { System.arraycopy(bytes, 1, data, 0, bytes.length - 1); } return new DERBitString(data, padBits); } }