class YBase64 {

    public static byte[] decode(byte[] inBytes) {

        if (null == inBytes) {
            throw new NullPointerException("Null input buffer");
        }

        /* Sanity check, should always be padded at the end. */
        int len = inBytes.length;
        if (len % 4 != 0 && inBytes[len - 1] == '\0') {
            len -= 1;
        }

        if (len % 4 != 0) {
            throw new CryptoException("String not padded ie, input string not modulo 4 len =  " + len
                            + " len%4= " + len % 4);
        }

        byte[] out = new byte[y64decodeLen(len)];

        int i = 0;
        int j = 0;
        int tlen;
        while (i < len) {
            tlen = (len - i);
            if (tlen > 4) {
                tlen = 4;
            }

            /* Figure out how long "tlen" really is */
            if (inBytes[i + 3] == '-') {
                tlen--;
            }
            if (inBytes[i + 2] == '-') {
                tlen--;
            }

            if (inBytes[i + 1] == '-') { /* This case should NEVER happen. */
                throw new CryptoException("Too Many pad characters ( this should never happen )");
            }

            /* decode */
            byte a = decodeByte(inBytes[i++]);
            byte b = decodeByte(inBytes[i++]);
            byte c = decodeByte(inBytes[i++]);
            byte d = decodeByte(inBytes[i++]);

            /* validate */
            if (a == (byte) 0xee || b == (byte) 0xee || c == (byte) 0xee || d == (byte) 0xee) {
                throw new CryptoException("Unrecognized characters in y64-encoded input starting at: " + (i - 4));
            }

            if (tlen == 4) {
                // dec1: ((a << 2) + (b >> 4));
                out[j++] = decode1(a, b);
                // dec2: ((b << 4) + (c >> 2));
                out[j++] = decode2(b, c);
                // dec3: ((c << 6) + d);
                out[j++] = decode3(c, d);
            } else if (tlen == 3) {
                if ((c & (byte) 0x03) != 0) {
                    throw new CryptoException("Unknown decode error c & 0x03 failed, c-pos: " + (i - 2));
                }
                // dec1: ((a << 2) + (b >> 4));
                out[j++] = decode1(a, b);
                // dec2: ((b << 4) + (c >> 2));
                out[j++] = decode2(b, c);
            } else { /* tlen == 2 */
                if ((b & (byte) 0x0F) != 0) {
                    throw new CryptoException("Invalid decode. b & 0x0f failed, b-pos: " + (i - 3));
                }
                // dec1: ((a << 2) + (b >> 4));
                out[j++] = decode1(a, b);
            }
        }
        
        return Arrays.copyOf(out, j);
    }

}