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        if (obj instanceof byte[])
30        {
31            try
32            {
33                return (DERBitString)fromByteArray((byte[])obj);
34            }
35            catch (Exception e)
36            {
37                throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
38            }
39        }
40
41        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
42    }
43
44    /**
45     * return a Bit String from a tagged object.
46     *
47     * @param obj the tagged object holding the object we want
48     * @param explicit true if the object is meant to be explicitly
49     *              tagged false otherwise.
50     * @exception IllegalArgumentException if the tagged object cannot
51     *               be converted.
52     * @return a DERBitString instance, or null.
53     */
54    public static DERBitString getInstance(
55        ASN1TaggedObject obj,
56        boolean          explicit)
57    {
58        ASN1Primitive o = obj.getObject();
59
60        if (explicit || o instanceof DERBitString)
61        {
62            return getInstance(o);
63        }
64        else
65        {
66            return fromOctetString(((ASN1OctetString)o).getOctets());
67        }
68    }
69
70    protected DERBitString(
71        byte    data,
72        int     padBits)
73    {
74        this(toByteArray(data), padBits);
75    }
76
77    private static byte[] toByteArray(byte data)
78    {
79        byte[] rv = new byte[1];
80
81        rv[0] = data;
82
83        return rv;
84    }
85
86    /**
87     * @param data the octets making up the bit string.
88     * @param padBits the number of extra bits at the end of the string.
89     */
90    public DERBitString(
91        byte[]  data,
92        int     padBits)
93    {
94        super(data, padBits);
95    }
96
97    public DERBitString(
98        byte[]  data)
99    {
100        this(data, 0);
101    }
102
103    public DERBitString(
104        int value)
105    {
106        super(getBytes(value), getPadBits(value));
107    }
108
109    public DERBitString(
110        ASN1Encodable obj)
111        throws IOException
112    {
113        super(obj.toASN1Primitive().getEncoded(ASN1Encoding.DER), 0);
114    }
115
116    boolean isConstructed()
117    {
118        return false;
119    }
120
121    int encodedLength()
122    {
123        return 1 + StreamUtil.calculateBodyLength(data.length + 1) + data.length + 1;
124    }
125
126    void encode(
127        ASN1OutputStream  out)
128        throws IOException
129    {
130        byte[] string = derForm(data, padBits);
131        byte[] bytes = new byte[string.length + 1];
132
133        bytes[0] = (byte)getPadBits();
134        System.arraycopy(string, 0, bytes, 1, bytes.length - 1);
135
136        out.writeEncoded(BERTags.BIT_STRING, bytes);
137    }
138
139    static DERBitString fromOctetString(byte[] bytes)
140    {
141        if (bytes.length < 1)
142        {
143            throw new IllegalArgumentException("truncated BIT STRING detected");
144        }
145
146        int padBits = bytes[0];
147        byte[] data = new byte[bytes.length - 1];
148
149        if (data.length != 0)
150        {
151            System.arraycopy(bytes, 1, data, 0, bytes.length - 1);
152        }
153
154        return new DERBitString(data, padBits);
155    }
156}
157