1package org.bouncycastle.asn1;
2
3import java.io.IOException;
4import java.math.BigInteger;
5
6import org.bouncycastle.util.Arrays;
7
8/**
9 * Class representing the ASN.1 ENUMERATED type.
10 */
11public class ASN1Enumerated
12    extends ASN1Primitive
13{
14    private final byte[] bytes;
15
16    /**
17     * return an enumerated from the passed in object
18     *
19     * @param obj an ASN1Enumerated or an object that can be converted into one.
20     * @exception IllegalArgumentException if the object cannot be converted.
21     * @return an ASN1Enumerated instance, or null.
22     */
23    public static ASN1Enumerated getInstance(
24        Object  obj)
25    {
26        if (obj == null || obj instanceof ASN1Enumerated)
27        {
28            return (ASN1Enumerated)obj;
29        }
30
31        if (obj instanceof byte[])
32        {
33            try
34            {
35                return (ASN1Enumerated)fromByteArray((byte[])obj);
36            }
37            catch (Exception e)
38            {
39                throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
40            }
41        }
42
43        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
44    }
45
46    /**
47     * return an Enumerated from a tagged object.
48     *
49     * @param obj the tagged object holding the object we want
50     * @param explicit true if the object is meant to be explicitly
51     *              tagged false otherwise.
52     * @exception IllegalArgumentException if the tagged object cannot
53     *               be converted.
54     * @return an ASN1Enumerated instance, or null.
55     */
56    public static ASN1Enumerated getInstance(
57        ASN1TaggedObject obj,
58        boolean          explicit)
59    {
60        ASN1Primitive o = obj.getObject();
61
62        if (explicit || o instanceof ASN1Enumerated)
63        {
64            return getInstance(o);
65        }
66        else
67        {
68            return fromOctetString(((ASN1OctetString)o).getOctets());
69        }
70    }
71
72    /**
73     * Constructor from int.
74     *
75     * @param value the value of this enumerated.
76     */
77    public ASN1Enumerated(
78        int         value)
79    {
80        bytes = BigInteger.valueOf(value).toByteArray();
81    }
82
83    /**
84     * Constructor from BigInteger
85     *
86     * @param value the value of this enumerated.
87     */
88    public ASN1Enumerated(
89        BigInteger   value)
90    {
91        bytes = value.toByteArray();
92    }
93
94    /**
95     * Constructor from encoded BigInteger.
96     *
97     * @param bytes the value of this enumerated as an encoded BigInteger (signed).
98     */
99    public ASN1Enumerated(
100        byte[]   bytes)
101    {
102        if (bytes.length > 1)
103        {
104            if (bytes[0] == 0 && (bytes[1] & 0x80) == 0)
105            {
106                throw new IllegalArgumentException("malformed enumerated");
107            }
108            if (bytes[0] == (byte)0xff && (bytes[1] & 0x80) != 0)
109            {
110                throw new IllegalArgumentException("malformed enumerated");
111            }
112        }
113        this.bytes = Arrays.clone(bytes);
114    }
115
116    public BigInteger getValue()
117    {
118        return new BigInteger(bytes);
119    }
120
121    boolean isConstructed()
122    {
123        return false;
124    }
125
126    int encodedLength()
127    {
128        return 1 + StreamUtil.calculateBodyLength(bytes.length) + bytes.length;
129    }
130
131    void encode(
132        ASN1OutputStream out)
133        throws IOException
134    {
135        out.writeEncoded(BERTags.ENUMERATED, bytes);
136    }
137
138    boolean asn1Equals(
139        ASN1Primitive  o)
140    {
141        if (!(o instanceof ASN1Enumerated))
142        {
143            return false;
144        }
145
146        ASN1Enumerated other = (ASN1Enumerated)o;
147
148        return Arrays.areEqual(this.bytes, other.bytes);
149    }
150
151    public int hashCode()
152    {
153        return Arrays.hashCode(bytes);
154    }
155
156    private static ASN1Enumerated[] cache = new ASN1Enumerated[12];
157
158    static ASN1Enumerated fromOctetString(byte[] enc)
159    {
160        if (enc.length > 1)
161        {
162            return new ASN1Enumerated(enc);
163        }
164
165        if (enc.length == 0)
166        {
167            throw new IllegalArgumentException("ENUMERATED has zero length");
168        }
169        int value = enc[0] & 0xff;
170
171        if (value >= cache.length)
172        {
173            return new ASN1Enumerated(Arrays.clone(enc));
174        }
175
176        ASN1Enumerated possibleMatch = cache[value];
177
178        if (possibleMatch == null)
179        {
180            possibleMatch = cache[value] = new ASN1Enumerated(Arrays.clone(enc));
181        }
182
183        return possibleMatch;
184    }
185}
186