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

package org.bouncycastle.util.encoders;

import org.bouncycastle.util.Strings;
import java.io.OutputStream;
import java.io.IOException;
import org.bouncycastle.util.Arrays;

public class Base32Encoder implements Encoder
{
    private static final byte[] DEAULT_ENCODING_TABLE;
    private static final byte DEFAULT_PADDING = 61;
    private final byte[] encodingTable;
    private final byte padding;
    private final byte[] decodingTable;
    
    protected void initialiseDecodingTable() {
        for (int i = 0; i < this.decodingTable.length; ++i) {
            this.decodingTable[i] = -1;
        }
        for (int j = 0; j < this.encodingTable.length; ++j) {
            this.decodingTable[this.encodingTable[j]] = (byte)j;
        }
    }
    
    public Base32Encoder() {
        this.decodingTable = new byte[128];
        this.encodingTable = Base32Encoder.DEAULT_ENCODING_TABLE;
        this.padding = 61;
        this.initialiseDecodingTable();
    }
    
    public Base32Encoder(final byte[] array, final byte padding) {
        this.decodingTable = new byte[128];
        if (array.length != 32) {
            throw new IllegalArgumentException("encoding table needs to be length 32");
        }
        this.encodingTable = Arrays.clone(array);
        this.padding = padding;
        this.initialiseDecodingTable();
    }
    
    public int encode(final byte[] array, final int n, final int n2, final byte[] array2, final int n3) throws IOException {
        int i;
        int n4;
        int n5;
        for (i = n, n4 = n + n2 - 4, n5 = n3; i < n4; i += 5, n5 += 8) {
            this.encodeBlock(array, i, array2, n5);
        }
        final int n6 = n2 - (i - n);
        if (n6 > 0) {
            final byte[] array3 = new byte[5];
            System.arraycopy(array, i, array3, 0, n6);
            this.encodeBlock(array3, 0, array2, n5);
            switch (n6) {
                case 1: {
                    array2[n5 + 2] = this.padding;
                    array2[n5 + 3] = this.padding;
                    array2[n5 + 4] = this.padding;
                    array2[n5 + 5] = this.padding;
                    array2[n5 + 6] = this.padding;
                    array2[n5 + 7] = this.padding;
                    break;
                }
                case 2: {
                    array2[n5 + 4] = this.padding;
                    array2[n5 + 5] = this.padding;
                    array2[n5 + 6] = this.padding;
                    array2[n5 + 7] = this.padding;
                    break;
                }
                case 3: {
                    array2[n5 + 5] = this.padding;
                    array2[n5 + 6] = this.padding;
                    array2[n5 + 7] = this.padding;
                    break;
                }
                case 4: {
                    array2[n5 + 7] = this.padding;
                    break;
                }
            }
            n5 += 8;
        }
        return n5 - n3;
    }
    
    private void encodeBlock(final byte[] array, int n, final byte[] array2, int n2) {
        final byte b = array[n++];
        final int n3 = array[n++] & 0xFF;
        final int n4 = array[n++] & 0xFF;
        final int n5 = array[n++] & 0xFF;
        final int n6 = array[n] & 0xFF;
        array2[n2++] = this.encodingTable[b >>> 3 & 0x1F];
        array2[n2++] = this.encodingTable[(b << 2 | n3 >>> 6) & 0x1F];
        array2[n2++] = this.encodingTable[n3 >>> 1 & 0x1F];
        array2[n2++] = this.encodingTable[(n3 << 4 | n4 >>> 4) & 0x1F];
        array2[n2++] = this.encodingTable[(n4 << 1 | n5 >>> 7) & 0x1F];
        array2[n2++] = this.encodingTable[n5 >>> 2 & 0x1F];
        array2[n2++] = this.encodingTable[(n5 << 3 | n6 >>> 5) & 0x1F];
        array2[n2] = this.encodingTable[n6 & 0x1F];
    }
    
    @Override
    public int getEncodedLength(final int n) {
        return (n + 4) / 5 * 8;
    }
    
    @Override
    public int getMaxDecodedLength(final int n) {
        return n / 8 * 5;
    }
    
    @Override
    public int encode(final byte[] array, int n, final int n2, final OutputStream outputStream) throws IOException {
        if (n2 < 0) {
            return 0;
        }
        final byte[] b = new byte[72];
        int min;
        for (int i = n2; i > 0; i -= min) {
            min = Math.min(45, i);
            outputStream.write(b, 0, this.encode(array, n, min, b, 0));
            n += min;
        }
        return (n2 + 2) / 3 * 4;
    }
    
    private boolean ignore(final char c) {
        return c == '\n' || c == '\r' || c == '\t' || c == ' ';
    }
    
    @Override
    public int decode(final byte[] array, final int n, final int n2, final OutputStream outputStream) throws IOException {
        final byte[] array2 = new byte[55];
        int len = 0;
        int n3 = 0;
        int n4;
        for (n4 = n + n2; n4 > n && this.ignore((char)array[n4 - 1]); --n4) {}
        if (n4 == 0) {
            return 0;
        }
        int n5;
        int n6;
        for (n5 = 0, n6 = n4; n6 > n && n5 != 8; --n6) {
            if (!this.ignore((char)array[n6 - 1])) {
                ++n5;
            }
        }
        int i;
        int nextI7;
        for (i = this.nextI(array, n, n6); i < n6; i = this.nextI(array, nextI7, n6)) {
            final byte b = this.decodingTable[array[i++]];
            int nextI = this.nextI(array, i, n6);
            final byte b2 = this.decodingTable[array[nextI++]];
            int nextI2 = this.nextI(array, nextI, n6);
            final byte b3 = this.decodingTable[array[nextI2++]];
            int nextI3 = this.nextI(array, nextI2, n6);
            final byte b4 = this.decodingTable[array[nextI3++]];
            int nextI4 = this.nextI(array, nextI3, n6);
            final byte b5 = this.decodingTable[array[nextI4++]];
            int nextI5 = this.nextI(array, nextI4, n6);
            final byte b6 = this.decodingTable[array[nextI5++]];
            int nextI6 = this.nextI(array, nextI5, n6);
            final byte b7 = this.decodingTable[array[nextI6++]];
            nextI7 = this.nextI(array, nextI6, n6);
            final byte b8 = this.decodingTable[array[nextI7++]];
            if ((b | b2 | b3 | b4 | b5 | b6 | b7 | b8) < 0) {
                throw new IOException("invalid characters encountered in base32 data");
            }
            array2[len++] = (byte)(b << 3 | b2 >> 2);
            array2[len++] = (byte)(b2 << 6 | b3 << 1 | b4 >> 4);
            array2[len++] = (byte)(b4 << 4 | b5 >> 1);
            array2[len++] = (byte)(b5 << 7 | b6 << 2 | b7 >> 3);
            array2[len++] = (byte)(b7 << 5 | b8);
            if (len == array2.length) {
                outputStream.write(array2);
                len = 0;
            }
            n3 += 5;
        }
        if (len > 0) {
            outputStream.write(array2, 0, len);
        }
        final int nextI8 = this.nextI(array, i, n4);
        final int nextI9 = this.nextI(array, nextI8 + 1, n4);
        final int nextI10 = this.nextI(array, nextI9 + 1, n4);
        final int nextI11 = this.nextI(array, nextI10 + 1, n4);
        final int nextI12 = this.nextI(array, nextI11 + 1, n4);
        final int nextI13 = this.nextI(array, nextI12 + 1, n4);
        final int nextI14 = this.nextI(array, nextI13 + 1, n4);
        return n3 + this.decodeLastBlock(outputStream, (char)array[nextI8], (char)array[nextI9], (char)array[nextI10], (char)array[nextI11], (char)array[nextI12], (char)array[nextI13], (char)array[nextI14], (char)array[this.nextI(array, nextI14 + 1, n4)]);
    }
    
    private int nextI(final byte[] array, int n, final int n2) {
        while (n < n2 && this.ignore((char)array[n])) {
            ++n;
        }
        return n;
    }
    
    @Override
    public int decode(final String s, final OutputStream outputStream) throws IOException {
        final byte[] byteArray = Strings.toByteArray(s);
        return this.decode(byteArray, 0, byteArray.length, outputStream);
    }
    
    private int decodeLastBlock(final OutputStream outputStream, final char c, final char c2, final char c3, final char c4, final char c5, final char c6, final char c7, final char c8) throws IOException {
        if (c8 == this.padding) {
            if (c7 != this.padding) {
                final byte b = this.decodingTable[c];
                final byte b2 = this.decodingTable[c2];
                final byte b3 = this.decodingTable[c3];
                final byte b4 = this.decodingTable[c4];
                final byte b5 = this.decodingTable[c5];
                final byte b6 = this.decodingTable[c6];
                final byte b7 = this.decodingTable[c7];
                if ((b | b2 | b3 | b4 | b5 | b6 | b7) < 0) {
                    throw new IOException("invalid characters encountered at end of base32 data");
                }
                outputStream.write(b << 3 | b2 >> 2);
                outputStream.write(b2 << 6 | b3 << 1 | b4 >> 4);
                outputStream.write(b4 << 4 | b5 >> 1);
                outputStream.write(b5 << 7 | b6 << 2 | b7 >> 3);
                return 4;
            }
            else {
                if (c6 != this.padding) {
                    throw new IOException("invalid characters encountered at end of base32 data");
                }
                if (c5 != this.padding) {
                    final byte b8 = this.decodingTable[c];
                    final byte b9 = this.decodingTable[c2];
                    final byte b10 = this.decodingTable[c3];
                    final byte b11 = this.decodingTable[c4];
                    final byte b12 = this.decodingTable[c5];
                    if ((b8 | b9 | b10 | b11 | b12) < 0) {
                        throw new IOException("invalid characters encountered at end of base32 data");
                    }
                    outputStream.write(b8 << 3 | b9 >> 2);
                    outputStream.write(b9 << 6 | b10 << 1 | b11 >> 4);
                    outputStream.write(b11 << 4 | b12 >> 1);
                    return 3;
                }
                else if (c4 != this.padding) {
                    final byte b13 = this.decodingTable[c];
                    final byte b14 = this.decodingTable[c2];
                    final byte b15 = this.decodingTable[c3];
                    final byte b16 = this.decodingTable[c4];
                    if ((b13 | b14 | b15 | b16) < 0) {
                        throw new IOException("invalid characters encountered at end of base32 data");
                    }
                    outputStream.write(b13 << 3 | b14 >> 2);
                    outputStream.write(b14 << 6 | b15 << 1 | b16 >> 4);
                    return 2;
                }
                else {
                    if (c3 != this.padding) {
                        throw new IOException("invalid characters encountered at end of base32 data");
                    }
                    final byte b17 = this.decodingTable[c];
                    final byte b18 = this.decodingTable[c2];
                    if ((b17 | b18) < 0) {
                        throw new IOException("invalid characters encountered at end of base32 data");
                    }
                    outputStream.write(b17 << 3 | b18 >> 2);
                    return 1;
                }
            }
        }
        else {
            final byte b19 = this.decodingTable[c];
            final byte b20 = this.decodingTable[c2];
            final byte b21 = this.decodingTable[c3];
            final byte b22 = this.decodingTable[c4];
            final byte b23 = this.decodingTable[c5];
            final byte b24 = this.decodingTable[c6];
            final byte b25 = this.decodingTable[c7];
            final byte b26 = this.decodingTable[c8];
            if ((b19 | b20 | b21 | b22 | b23 | b24 | b25 | b26) < 0) {
                throw new IOException("invalid characters encountered at end of base32 data");
            }
            outputStream.write(b19 << 3 | b20 >> 2);
            outputStream.write(b20 << 6 | b21 << 1 | b22 >> 4);
            outputStream.write(b22 << 4 | b23 >> 1);
            outputStream.write(b23 << 7 | b24 << 2 | b25 >> 3);
            outputStream.write(b25 << 5 | b26);
            return 5;
        }
    }
    
    static {
        DEAULT_ENCODING_TABLE = new byte[] { 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 50, 51, 52, 53, 54, 55 };
    }
}
