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 INTEGER type.
10 */
11public class ASN1Integer
12    extends ASN1Primitive
13{
14    byte[] bytes;
15
16    /**
17     * return an integer from the passed in object
18     *
19     * @param obj an ASN1Integer or an object that can be converted into one.
20     * @throws IllegalArgumentException if the object cannot be converted.
21     * @return an ASN1Integer instance.
22     */
23    public static ASN1Integer getInstance(
24        Object obj)
25    {
26        if (obj == null || obj instanceof ASN1Integer)
27        {
28            return (ASN1Integer)obj;
29        }
30
31        if (obj instanceof byte[])
32        {
33            try
34            {
35                return (ASN1Integer)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 Integer 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     * @throws IllegalArgumentException if the tagged object cannot
53     * be converted.
54     * @return an ASN1Integer instance.
55     */
56    public static ASN1Integer getInstance(
57        ASN1TaggedObject obj,
58        boolean explicit)
59    {
60        ASN1Primitive o = obj.getObject();
61
62        if (explicit || o instanceof ASN1Integer)
63        {
64            return getInstance(o);
65        }
66        else
67        {
68            return new ASN1Integer(ASN1OctetString.getInstance(obj.getObject()).getOctets());
69        }
70    }
71
72    public ASN1Integer(
73        long value)
74    {
75        bytes = BigInteger.valueOf(value).toByteArray();
76    }
77
78    public ASN1Integer(
79        BigInteger value)
80    {
81        bytes = value.toByteArray();
82    }
83
84    public ASN1Integer(
85        byte[] bytes)
86    {
87        this(bytes, true);
88    }
89
90    ASN1Integer(byte[] bytes, boolean clone)
91    {
92        this.bytes = (clone) ? Arrays.clone(bytes) : bytes;
93    }
94
95    public BigInteger getValue()
96    {
97        return new BigInteger(bytes);
98    }
99
100    /**
101     * in some cases positive values get crammed into a space,
102     * that's not quite big enough...
103     * @return the BigInteger that results from treating this ASN.1 INTEGER as unsigned.
104     */
105    public BigInteger getPositiveValue()
106    {
107        return new BigInteger(1, bytes);
108    }
109
110    boolean isConstructed()
111    {
112        return false;
113    }
114
115    int encodedLength()
116    {
117        return 1 + StreamUtil.calculateBodyLength(bytes.length) + bytes.length;
118    }
119
120    void encode(
121        ASN1OutputStream out)
122        throws IOException
123    {
124        out.writeEncoded(BERTags.INTEGER, bytes);
125    }
126
127    public int hashCode()
128    {
129        int value = 0;
130
131        for (int i = 0; i != bytes.length; i++)
132        {
133            value ^= (bytes[i] & 0xff) << (i % 4);
134        }
135
136        return value;
137    }
138
139    boolean asn1Equals(
140        ASN1Primitive o)
141    {
142        if (!(o instanceof ASN1Integer))
143        {
144            return false;
145        }
146
147        ASN1Integer other = (ASN1Integer)o;
148
149        return Arrays.areEqual(bytes, other.bytes);
150    }
151
152    public String toString()
153    {
154        return getValue().toString();
155    }
156
157}
158