// 
// Decompiled by Procyon v0.6.0
// 

package org.bouncycastle.asn1;

import org.bouncycastle.util.Properties;
import java.io.IOException;
import org.bouncycastle.util.Arrays;
import java.math.BigInteger;

public class ASN1Integer extends ASN1Primitive
{
    static final ASN1UniversalType TYPE;
    static final int SIGN_EXT_SIGNED = -1;
    static final int SIGN_EXT_UNSIGNED = 255;
    private final byte[] bytes;
    private final int start;
    
    public static ASN1Integer getInstance(final Object o) {
        if (o == null || o instanceof ASN1Integer) {
            return (ASN1Integer)o;
        }
        if (o instanceof byte[]) {
            try {
                return (ASN1Integer)ASN1Integer.TYPE.fromByteArray((byte[])o);
            }
            catch (final Exception ex) {
                throw new IllegalArgumentException("encoding error in getInstance: " + ex.toString());
            }
        }
        throw new IllegalArgumentException("illegal object in getInstance: " + o.getClass().getName());
    }
    
    public static ASN1Integer getInstance(final ASN1TaggedObject asn1TaggedObject, final boolean b) {
        return (ASN1Integer)ASN1Integer.TYPE.getContextTagged(asn1TaggedObject, b);
    }
    
    public static ASN1Integer getTagged(final ASN1TaggedObject asn1TaggedObject, final boolean b) {
        return (ASN1Integer)ASN1Integer.TYPE.getTagged(asn1TaggedObject, b);
    }
    
    public ASN1Integer(final long val) {
        this.bytes = BigInteger.valueOf(val).toByteArray();
        this.start = 0;
    }
    
    public ASN1Integer(final BigInteger bigInteger) {
        this.bytes = bigInteger.toByteArray();
        this.start = 0;
    }
    
    public ASN1Integer(final byte[] array) {
        this(array, true);
    }
    
    ASN1Integer(final byte[] array, final boolean b) {
        if (isMalformed(array)) {
            throw new IllegalArgumentException("malformed integer");
        }
        this.bytes = (b ? Arrays.clone(array) : array);
        this.start = signBytesToSkip(array);
    }
    
    public BigInteger getPositiveValue() {
        return new BigInteger(1, this.bytes);
    }
    
    public BigInteger getValue() {
        return new BigInteger(this.bytes);
    }
    
    public boolean hasValue(final int n) {
        return this.bytes.length - this.start <= 4 && intValue(this.bytes, this.start, -1) == n;
    }
    
    public boolean hasValue(final long n) {
        return this.bytes.length - this.start <= 8 && longValue(this.bytes, this.start, -1) == n;
    }
    
    public boolean hasValue(final BigInteger x) {
        return null != x && intValue(this.bytes, this.start, -1) == x.intValue() && this.getValue().equals(x);
    }
    
    public int intPositiveValueExact() {
        final int n = this.bytes.length - this.start;
        if (n > 4 || (n == 4 && 0x0 != (this.bytes[this.start] & 0x80))) {
            throw new ArithmeticException("ASN.1 Integer out of positive int range");
        }
        return intValue(this.bytes, this.start, 255);
    }
    
    public int intValueExact() {
        if (this.bytes.length - this.start > 4) {
            throw new ArithmeticException("ASN.1 Integer out of int range");
        }
        return intValue(this.bytes, this.start, -1);
    }
    
    public long longValueExact() {
        if (this.bytes.length - this.start > 8) {
            throw new ArithmeticException("ASN.1 Integer out of long range");
        }
        return longValue(this.bytes, this.start, -1);
    }
    
    @Override
    boolean encodeConstructed() {
        return false;
    }
    
    @Override
    int encodedLength(final boolean b) {
        return ASN1OutputStream.getLengthOfEncodingDL(b, this.bytes.length);
    }
    
    @Override
    void encode(final ASN1OutputStream asn1OutputStream, final boolean b) throws IOException {
        asn1OutputStream.writeEncodingDL(b, 2, this.bytes);
    }
    
    @Override
    public int hashCode() {
        return Arrays.hashCode(this.bytes);
    }
    
    @Override
    boolean asn1Equals(final ASN1Primitive asn1Primitive) {
        return asn1Primitive instanceof ASN1Integer && Arrays.areEqual(this.bytes, ((ASN1Integer)asn1Primitive).bytes);
    }
    
    @Override
    public String toString() {
        return this.getValue().toString();
    }
    
    static ASN1Integer createPrimitive(final byte[] array) {
        return new ASN1Integer(array, false);
    }
    
    static int intValue(final byte[] array, final int a, final int n) {
        final int length = array.length;
        int max = Math.max(a, length - 4);
        int n2 = array[max] & n;
        while (++max < length) {
            n2 = (n2 << 8 | (array[max] & 0xFF));
        }
        return n2;
    }
    
    static long longValue(final byte[] array, final int a, final int n) {
        final int length = array.length;
        int max = Math.max(a, length - 8);
        long n2 = array[max] & n;
        while (++max < length) {
            n2 = (n2 << 8 | (long)(array[max] & 0xFF));
        }
        return n2;
    }
    
    static boolean isMalformed(final byte[] array) {
        switch (array.length) {
            case 0: {
                return true;
            }
            case 1: {
                return false;
            }
            default: {
                return array[0] == array[1] >> 7 && !Properties.isOverrideSet("org.bouncycastle.asn1.allow_unsafe_integer");
            }
        }
    }
    
    static int signBytesToSkip(final byte[] array) {
        int n;
        for (n = 0; n < array.length - 1 && array[n] == array[n + 1] >> 7; ++n) {}
        return n;
    }
    
    static {
        TYPE = new ASN1UniversalType(2) {
            @Override
            ASN1Primitive fromImplicitPrimitive(final DEROctetString derOctetString) {
                return ASN1Integer.createPrimitive(derOctetString.getOctets());
            }
        };
    }
}
