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

package org.bouncycastle.crypto;

public class DefaultBufferedBlockCipher extends BufferedBlockCipher
{
    protected byte[] buf;
    protected int bufOff;
    protected boolean forEncryption;
    protected BlockCipher cipher;
    protected MultiBlockCipher mbCipher;
    protected boolean partialBlockOkay;
    protected boolean pgpCFB;
    
    protected DefaultBufferedBlockCipher() {
    }
    
    public DefaultBufferedBlockCipher(final BlockCipher cipher) {
        this.cipher = cipher;
        if (cipher instanceof MultiBlockCipher) {
            this.mbCipher = (MultiBlockCipher)cipher;
            this.buf = new byte[this.mbCipher.getMultiBlockSize()];
        }
        else {
            this.mbCipher = null;
            this.buf = new byte[cipher.getBlockSize()];
        }
        this.bufOff = 0;
        final String algorithmName = cipher.getAlgorithmName();
        final int n = algorithmName.indexOf(47) + 1;
        this.pgpCFB = (n > 0 && algorithmName.startsWith("PGP", n));
        if (this.pgpCFB || cipher instanceof StreamCipher) {
            this.partialBlockOkay = true;
        }
        else {
            this.partialBlockOkay = (n > 0 && algorithmName.startsWith("OpenPGP", n));
        }
    }
    
    @Override
    public BlockCipher getUnderlyingCipher() {
        return this.cipher;
    }
    
    @Override
    public void init(final boolean forEncryption, final CipherParameters cipherParameters) throws IllegalArgumentException {
        this.forEncryption = forEncryption;
        this.reset();
        this.cipher.init(forEncryption, cipherParameters);
    }
    
    @Override
    public int getBlockSize() {
        return this.cipher.getBlockSize();
    }
    
    @Override
    public int getUpdateOutputSize(final int n) {
        final int n2 = n + this.bufOff;
        int n3;
        if (this.pgpCFB) {
            if (this.forEncryption) {
                n3 = n2 % this.buf.length - (this.cipher.getBlockSize() + 2);
            }
            else {
                n3 = n2 % this.buf.length;
            }
        }
        else {
            n3 = n2 % this.buf.length;
        }
        return n2 - n3;
    }
    
    @Override
    public int getOutputSize(final int n) {
        if (this.pgpCFB && this.forEncryption) {
            return n + this.bufOff + (this.cipher.getBlockSize() + 2);
        }
        return n + this.bufOff;
    }
    
    @Override
    public int processByte(final byte b, final byte[] array, final int n) throws DataLengthException, IllegalStateException {
        int processBuffer = 0;
        this.buf[this.bufOff++] = b;
        if (this.bufOff == this.buf.length) {
            processBuffer = this.processBuffer(array, n);
        }
        return processBuffer;
    }
    
    @Override
    public int processBytes(byte[] array, int n, int i, final byte[] array2, final int n2) throws DataLengthException, IllegalStateException {
        if (i < 0) {
            throw new IllegalArgumentException("Can't have a negative input length!");
        }
        final int blockSize = this.getBlockSize();
        final int updateOutputSize = this.getUpdateOutputSize(i);
        if (updateOutputSize > 0 && n2 + updateOutputSize > array2.length) {
            throw new OutputLengthException("output buffer too short");
        }
        int n3 = 0;
        final int n4 = this.buf.length - this.bufOff;
        if (i > n4) {
            if (this.bufOff != 0) {
                System.arraycopy(array, n, this.buf, this.bufOff, n4);
                n += n4;
                i -= n4;
            }
            if (array == array2) {
                array = new byte[i];
                System.arraycopy(array2, n, array, 0, i);
                n = 0;
            }
            if (this.bufOff != 0) {
                n3 += this.processBuffer(array2, n2);
            }
            if (this.mbCipher != null) {
                final int n5 = i / this.mbCipher.getMultiBlockSize() * (this.mbCipher.getMultiBlockSize() / blockSize);
                if (n5 > 0) {
                    n3 += this.mbCipher.processBlocks(array, n, n5, array2, n2 + n3);
                    final int n6 = n5 * blockSize;
                    i -= n6;
                    n += n6;
                }
            }
            else {
                while (i > this.buf.length) {
                    n3 += this.cipher.processBlock(array, n, array2, n2 + n3);
                    i -= blockSize;
                    n += blockSize;
                }
            }
        }
        System.arraycopy(array, n, this.buf, this.bufOff, i);
        this.bufOff += i;
        if (this.bufOff == this.buf.length) {
            n3 += this.processBuffer(array2, n2 + n3);
        }
        return n3;
    }
    
    private int processBuffer(final byte[] array, final int n) {
        this.bufOff = 0;
        if (this.mbCipher != null) {
            return this.mbCipher.processBlocks(this.buf, 0, this.buf.length / this.mbCipher.getBlockSize(), array, n);
        }
        return this.cipher.processBlock(this.buf, 0, array, n);
    }
    
    @Override
    public int doFinal(final byte[] array, final int n) throws DataLengthException, IllegalStateException, InvalidCipherTextException {
        try {
            int n2 = 0;
            if (n + this.bufOff > array.length) {
                throw new OutputLengthException("output buffer too short for doFinal()");
            }
            if (this.bufOff != 0) {
                int n3 = 0;
                if (this.mbCipher != null) {
                    final int n4 = this.bufOff / this.mbCipher.getBlockSize();
                    n2 += this.mbCipher.processBlocks(this.buf, 0, n4, array, n);
                    n3 = n4 * this.mbCipher.getBlockSize();
                }
                if (this.bufOff != n3) {
                    if (!this.partialBlockOkay) {
                        throw new DataLengthException("data not block size aligned");
                    }
                    this.cipher.processBlock(this.buf, n3, this.buf, n3);
                    System.arraycopy(this.buf, n3, array, n + n2, this.bufOff - n3);
                    n2 += this.bufOff - n3;
                    this.bufOff = 0;
                }
            }
            return n2;
        }
        finally {
            this.reset();
        }
    }
    
    @Override
    public void reset() {
        for (int i = 0; i < this.buf.length; ++i) {
            this.buf[i] = 0;
        }
        this.bufOff = 0;
        this.cipher.reset();
    }
}
