1package org.bouncycastle.asn1;
2
3import java.io.IOException;
4
5import org.bouncycastle.util.Arrays;
6
7/**
8 * Public facade of ASN.1 Boolean data.
9 * <p>
10 * Use following to place a new instance of ASN.1 Boolean in your dataset:
11 * <ul>
12 * <li> ASN1Boolean.TRUE literal</li>
13 * <li> ASN1Boolean.FALSE literal</li>
14 * <li> {@link ASN1Boolean#getInstance(boolean) ASN1Boolean.getInstance(boolean)}</li>
15 * <li> {@link ASN1Boolean#getInstance(int) ASN1Boolean.getInstance(int)}</li>
16 * </ul>
17 * </p>
18 */
19public class ASN1Boolean
20    extends ASN1Primitive
21{
22    private static final byte[] TRUE_VALUE = new byte[] { (byte)0xff };
23    private static final byte[] FALSE_VALUE = new byte[] { 0 };
24
25    private final byte[]         value;
26
27    public static final ASN1Boolean FALSE = new ASN1Boolean(false);
28    public static final ASN1Boolean TRUE  = new ASN1Boolean(true);
29
30    /**
31     * return a boolean from the passed in object.
32     *
33     * @param obj an ASN1Boolean or an object that can be converted into one.
34     * @exception IllegalArgumentException if the object cannot be converted.
35     * @return an ASN1Boolean instance.
36     */
37    public static ASN1Boolean getInstance(
38        Object  obj)
39    {
40        if (obj == null || obj instanceof ASN1Boolean)
41        {
42            return (ASN1Boolean)obj;
43        }
44
45        if (obj instanceof byte[])
46        {
47            byte[] enc = (byte[])obj;
48            try
49            {
50                return (ASN1Boolean)fromByteArray(enc);
51            }
52            catch (IOException e)
53            {
54                throw new IllegalArgumentException("failed to construct boolean from byte[]: " + e.getMessage());
55            }
56        }
57
58        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
59    }
60
61    /**
62     * return an ASN1Boolean from the passed in boolean.
63     * @param value true or false depending on the ASN1Boolean wanted.
64     * @return an ASN1Boolean instance.
65     */
66    public static ASN1Boolean getInstance(
67        boolean  value)
68    {
69        return (value ? TRUE : FALSE);
70    }
71
72    /**
73     * return an ASN1Boolean from the passed in value.
74     * @param value non-zero (true) or zero (false) depending on the ASN1Boolean wanted.
75     * @return an ASN1Boolean instance.
76     */
77    public static ASN1Boolean getInstance(
78        int value)
79    {
80        return (value != 0 ? TRUE : FALSE);
81    }
82
83    // BEGIN Android-added: Unknown reason
84    /**
85     * return a ASN1Boolean from the passed in array.
86     */
87    public static ASN1Boolean getInstance(
88        byte[] octets)
89    {
90        return (octets[0] != 0) ? TRUE : FALSE;
91    }
92
93    // END Android-added: Unknown reason
94    /**
95     * return a Boolean from a tagged object.
96     *
97     * @param obj the tagged object holding the object we want
98     * @param explicit true if the object is meant to be explicitly
99     *              tagged false otherwise.
100     * @exception IllegalArgumentException if the tagged object cannot
101     *               be converted.
102     * @return an ASN1Boolean instance.
103     */
104    public static ASN1Boolean getInstance(
105        ASN1TaggedObject obj,
106        boolean          explicit)
107    {
108        ASN1Primitive o = obj.getObject();
109
110        if (explicit || o instanceof ASN1Boolean)
111        {
112            return getInstance(o);
113        }
114        else
115        {
116            return ASN1Boolean.fromOctetString(((ASN1OctetString)o).getOctets());
117        }
118    }
119
120    ASN1Boolean(
121        byte[] value)
122    {
123        if (value.length != 1)
124        {
125            throw new IllegalArgumentException("byte value should have 1 byte in it");
126        }
127
128        if (value[0] == 0)
129        {
130            this.value = FALSE_VALUE;
131        }
132        else if ((value[0] & 0xff) == 0xff)
133        {
134            this.value = TRUE_VALUE;
135        }
136        else
137        {
138            this.value = Arrays.clone(value);
139        }
140    }
141
142    /**
143     * @deprecated use getInstance(boolean) method.
144     * @param value true or false.
145     */
146    // Android-changed: Reduce visibility to protected
147    protected ASN1Boolean(
148        boolean     value)
149    {
150        this.value = (value) ? TRUE_VALUE : FALSE_VALUE;
151    }
152
153    public boolean isTrue()
154    {
155        return (value[0] != 0);
156    }
157
158    boolean isConstructed()
159    {
160        return false;
161    }
162
163    int encodedLength()
164    {
165        return 3;
166    }
167
168    void encode(
169        ASN1OutputStream out)
170        throws IOException
171    {
172        out.writeEncoded(BERTags.BOOLEAN, value);
173    }
174
175    protected boolean asn1Equals(
176        ASN1Primitive  o)
177    {
178        if (o instanceof ASN1Boolean)
179        {
180            return (value[0] == ((ASN1Boolean)o).value[0]);
181        }
182
183        return false;
184    }
185
186    public int hashCode()
187    {
188        return value[0];
189    }
190
191
192    public String toString()
193    {
194      return (value[0] != 0) ? "TRUE" : "FALSE";
195    }
196
197    static ASN1Boolean fromOctetString(byte[] value)
198    {
199        if (value.length != 1)
200        {
201            throw new IllegalArgumentException("BOOLEAN value should have 1 byte in it");
202        }
203
204        if (value[0] == 0)
205        {
206            return FALSE;
207        }
208        else if ((value[0] & 0xff) == 0xff)
209        {
210            return TRUE;
211        }
212        else
213        {
214            return new ASN1Boolean(value);
215        }
216    }
217}
218