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    private final 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        if (bytes.length > 1)
93        {
94            if (bytes[0] == 0 && (bytes[1] & 0x80) == 0)
95            {
96                throw new IllegalArgumentException("malformed integer");
97            }
98            if (bytes[0] == (byte)0xff && (bytes[1] & 0x80) != 0)
99            {
100                throw new IllegalArgumentException("malformed integer");
101            }
102        }
103        this.bytes = (clone) ? Arrays.clone(bytes) : bytes;
104    }
105
106    public BigInteger getValue()
107    {
108        return new BigInteger(bytes);
109    }
110
111    /**
112     * in some cases positive values get crammed into a space,
113     * that's not quite big enough...
114     * @return the BigInteger that results from treating this ASN.1 INTEGER as unsigned.
115     */
116    public BigInteger getPositiveValue()
117    {
118        return new BigInteger(1, 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.INTEGER, bytes);
136    }
137
138    public int hashCode()
139    {
140        int value = 0;
141
142        for (int i = 0; i != bytes.length; i++)
143        {
144            value ^= (bytes[i] & 0xff) << (i % 4);
145        }
146
147        return value;
148    }
149
150    boolean asn1Equals(
151        ASN1Primitive o)
152    {
153        if (!(o instanceof ASN1Integer))
154        {
155            return false;
156        }
157
158        ASN1Integer other = (ASN1Integer)o;
159
160        return Arrays.areEqual(bytes, other.bytes);
161    }
162
163    public String toString()
164    {
165        return getValue().toString();
166    }
167
168}
169