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

package org.bouncycastle.asn1;

import java.io.IOException;
import java.io.ByteArrayInputStream;
import java.io.InputStream;

public class ASN1StreamParser
{
    private final InputStream _in;
    private final int _limit;
    private final byte[][] tmpBuffers;
    
    public ASN1StreamParser(final InputStream inputStream) {
        this(inputStream, StreamUtil.findLimit(inputStream));
    }
    
    public ASN1StreamParser(final byte[] buf) {
        this(new ByteArrayInputStream(buf), buf.length);
    }
    
    public ASN1StreamParser(final InputStream inputStream, final int n) {
        this(inputStream, n, new byte[11][]);
    }
    
    ASN1StreamParser(final InputStream in, final int limit, final byte[][] tmpBuffers) {
        this._in = in;
        this._limit = limit;
        this.tmpBuffers = tmpBuffers;
    }
    
    public ASN1Encodable readObject() throws IOException {
        final int read = this._in.read();
        if (read < 0) {
            return null;
        }
        return this.implParseObject(read);
    }
    
    ASN1Encodable implParseObject(final int n) throws IOException {
        this.set00Check(false);
        final int tagNumber = ASN1InputStream.readTagNumber(this._in, n);
        final int length = ASN1InputStream.readLength(this._in, this._limit, tagNumber == 3 || tagNumber == 4 || tagNumber == 16 || tagNumber == 17 || tagNumber == 8);
        if (length < 0) {
            if (0x0 == (n & 0x20)) {
                throw new IOException("indefinite-length primitive encoding encountered");
            }
            final ASN1StreamParser asn1StreamParser = new ASN1StreamParser(new IndefiniteLengthInputStream(this._in, this._limit), this._limit, this.tmpBuffers);
            final int n2 = n & 0xC0;
            if (n2 != 0) {
                return new BERTaggedObjectParser(n2, tagNumber, asn1StreamParser);
            }
            return asn1StreamParser.parseImplicitConstructedIL(tagNumber);
        }
        else {
            final DefiniteLengthInputStream definiteLengthInputStream = new DefiniteLengthInputStream(this._in, length, this._limit);
            if (0x0 == (n & 0xE0)) {
                return this.parseImplicitPrimitive(tagNumber, definiteLengthInputStream);
            }
            final ASN1StreamParser asn1StreamParser2 = new ASN1StreamParser(definiteLengthInputStream, definiteLengthInputStream.getLimit(), this.tmpBuffers);
            final int n3 = n & 0xC0;
            if (n3 != 0) {
                return new DLTaggedObjectParser(n3, tagNumber, (n & 0x20) != 0x0, asn1StreamParser2);
            }
            return asn1StreamParser2.parseImplicitConstructedDL(tagNumber);
        }
    }
    
    ASN1Primitive loadTaggedDL(final int n, final int n2, final boolean b) throws IOException {
        if (!b) {
            return ASN1TaggedObject.createPrimitive(n, n2, ((DefiniteLengthInputStream)this._in).toByteArray());
        }
        return ASN1TaggedObject.createConstructedDL(n, n2, this.readVector());
    }
    
    ASN1Primitive loadTaggedIL(final int n, final int n2) throws IOException {
        return ASN1TaggedObject.createConstructedIL(n, n2, this.readVector());
    }
    
    ASN1Encodable parseImplicitConstructedDL(final int i) throws IOException {
        switch (i) {
            case 3: {
                return new BERBitStringParser(this);
            }
            case 8: {
                return new DERExternalParser(this);
            }
            case 4: {
                return new BEROctetStringParser(this);
            }
            case 17: {
                return new DLSetParser(this);
            }
            case 16: {
                return new DLSequenceParser(this);
            }
            default: {
                throw new ASN1Exception("unknown DL object encountered: 0x" + Integer.toHexString(i));
            }
        }
    }
    
    ASN1Encodable parseImplicitConstructedIL(final int i) throws IOException {
        switch (i) {
            case 3: {
                return new BERBitStringParser(this);
            }
            case 4: {
                return new BEROctetStringParser(this);
            }
            case 8: {
                return new DERExternalParser(this);
            }
            case 16: {
                return new BERSequenceParser(this);
            }
            case 17: {
                return new BERSetParser(this);
            }
            default: {
                throw new ASN1Exception("unknown BER object encountered: 0x" + Integer.toHexString(i));
            }
        }
    }
    
    ASN1Encodable parseImplicitPrimitive(final int n) throws IOException {
        return this.parseImplicitPrimitive(n, (DefiniteLengthInputStream)this._in);
    }
    
    ASN1Encodable parseImplicitPrimitive(final int n, final DefiniteLengthInputStream definiteLengthInputStream) throws IOException {
        switch (n) {
            case 3: {
                return new DLBitStringParser(definiteLengthInputStream);
            }
            case 8: {
                throw new ASN1Exception("externals must use constructed encoding (see X.690 8.18)");
            }
            case 4: {
                return new DEROctetStringParser(definiteLengthInputStream);
            }
            case 17: {
                throw new ASN1Exception("sequences must use constructed encoding (see X.690 8.9.1/8.10.1)");
            }
            case 16: {
                throw new ASN1Exception("sets must use constructed encoding (see X.690 8.11.1/8.12.1)");
            }
            default: {
                try {
                    return ASN1InputStream.createPrimitiveDERObject(n, definiteLengthInputStream, this.tmpBuffers);
                }
                catch (final IllegalArgumentException ex) {
                    throw new ASN1Exception("corrupted stream detected", ex);
                }
                break;
            }
        }
    }
    
    ASN1Encodable parseObject(final int i) throws IOException {
        if (i < 0 || i > 30) {
            throw new IllegalArgumentException("invalid universal tag number: " + i);
        }
        final int read = this._in.read();
        if (read < 0) {
            return null;
        }
        if ((read & 0xFFFFFFDF) != i) {
            throw new IOException("unexpected identifier encountered: " + read);
        }
        return this.implParseObject(read);
    }
    
    ASN1TaggedObjectParser parseTaggedObject() throws IOException {
        final int read = this._in.read();
        if (read < 0) {
            return null;
        }
        if (0x0 == (read & 0xC0)) {
            throw new ASN1Exception("no tagged object found");
        }
        return (ASN1TaggedObjectParser)this.implParseObject(read);
    }
    
    ASN1EncodableVector readVector() throws IOException {
        int n = this._in.read();
        if (n < 0) {
            return new ASN1EncodableVector(0);
        }
        final ASN1EncodableVector asn1EncodableVector = new ASN1EncodableVector();
        do {
            final ASN1Encodable implParseObject = this.implParseObject(n);
            if (implParseObject instanceof InMemoryRepresentable) {
                asn1EncodableVector.add(((InMemoryRepresentable)implParseObject).getLoadedObject());
            }
            else {
                asn1EncodableVector.add(implParseObject.toASN1Primitive());
            }
        } while ((n = this._in.read()) >= 0);
        return asn1EncodableVector;
    }
    
    private void set00Check(final boolean eofOn00) {
        if (this._in instanceof IndefiniteLengthInputStream) {
            ((IndefiniteLengthInputStream)this._in).setEofOn00(eofOn00);
        }
    }
}
