1package org.bouncycastle.asn1;
2
3import java.io.IOException;
4
5/**
6 * A BIT STRING with DER encoding.
7 */
8public class DERBitString
9    extends ASN1BitString
10{
11    /**
12     * return a Bit String from the passed in object
13     *
14     * @param obj a DERBitString or an object that can be converted into one.
15     * @exception IllegalArgumentException if the object cannot be converted.
16     * @return a DERBitString instance, or null.
17     */
18    public static DERBitString getInstance(
19        Object  obj)
20    {
21        if (obj == null || obj instanceof DERBitString)
22        {
23            return (DERBitString)obj;
24        }
25        if (obj instanceof DLBitString)
26        {
27            return new DERBitString(((DLBitString)obj).data, ((DLBitString)obj).padBits);
28        }
29
30        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
31    }
32
33    /**
34     * return a Bit String from a tagged object.
35     *
36     * @param obj the tagged object holding the object we want
37     * @param explicit true if the object is meant to be explicitly
38     *              tagged false otherwise.
39     * @exception IllegalArgumentException if the tagged object cannot
40     *               be converted.
41     * @return a DERBitString instance, or null.
42     */
43    public static DERBitString getInstance(
44        ASN1TaggedObject obj,
45        boolean          explicit)
46    {
47        ASN1Primitive o = obj.getObject();
48
49        if (explicit || o instanceof DERBitString)
50        {
51            return getInstance(o);
52        }
53        else
54        {
55            return fromOctetString(((ASN1OctetString)o).getOctets());
56        }
57    }
58
59    protected DERBitString(
60        byte    data,
61        int     padBits)
62    {
63        this(toByteArray(data), padBits);
64    }
65
66    private static byte[] toByteArray(byte data)
67    {
68        byte[] rv = new byte[1];
69
70        rv[0] = data;
71
72        return rv;
73    }
74
75    /**
76     * @param data the octets making up the bit string.
77     * @param padBits the number of extra bits at the end of the string.
78     */
79    public DERBitString(
80        byte[]  data,
81        int     padBits)
82    {
83        super(data, padBits);
84    }
85
86    public DERBitString(
87        byte[]  data)
88    {
89        this(data, 0);
90    }
91
92    public DERBitString(
93        int value)
94    {
95        super(getBytes(value), getPadBits(value));
96    }
97
98    public DERBitString(
99        ASN1Encodable obj)
100        throws IOException
101    {
102        super(obj.toASN1Primitive().getEncoded(ASN1Encoding.DER), 0);
103    }
104
105    boolean isConstructed()
106    {
107        return false;
108    }
109
110    int encodedLength()
111    {
112        return 1 + StreamUtil.calculateBodyLength(data.length + 1) + data.length + 1;
113    }
114
115    void encode(
116        ASN1OutputStream  out)
117        throws IOException
118    {
119        byte[] string = derForm(data, padBits);
120        byte[] bytes = new byte[string.length + 1];
121
122        bytes[0] = (byte)getPadBits();
123        System.arraycopy(string, 0, bytes, 1, bytes.length - 1);
124
125        out.writeEncoded(BERTags.BIT_STRING, bytes);
126    }
127
128    static DERBitString fromOctetString(byte[] bytes)
129    {
130        if (bytes.length < 1)
131        {
132            throw new IllegalArgumentException("truncated BIT STRING detected");
133        }
134
135        int padBits = bytes[0];
136        byte[] data = new byte[bytes.length - 1];
137
138        if (data.length != 0)
139        {
140            System.arraycopy(bytes, 1, data, 0, bytes.length - 1);
141        }
142
143        return new DERBitString(data, padBits);
144    }
145}
146