Base64Engine.java 11.2 KB
/*
 * Decompiled with CFR 0_118.
 */
package com.adobe.internal.util.base64;

public class Base64Engine {
    private static final byte ED = 64;
    private static final byte IL = 65;
    private static byte[] base64DecodeTable;
    private static byte[] base64EncodeTable;
    private LineEnding lineEnd = LineEnding.CR;
    private int lineLength = 76;
    boolean lineEndsAtBreaks = false;
    private static char[] bitsToChar;
    private static final byte[] charToBits;

    public Base64Engine() {
    }

    public Base64Engine(int lineLength, LineEnding lineEnd) {
        this.lineLength = lineLength;
        this.lineEnd = lineEnd;
    }

    public Base64Engine(int lineLength, LineEnding lineEnd, boolean lineEndsAtBreaks) {
        this(lineLength, lineEnd);
        this.lineEndsAtBreaks = lineEndsAtBreaks;
    }

    public int decode(byte[] input, int inOffset, int inLength, byte[] output, int outOffset) {
        return this.decode(input, inOffset, inLength, output, outOffset, output.length);
    }

    public int decode(byte[] input, int inOffset, int inLength, byte[] output, int outOffset, int outLength) {
        return this.decode(input, inOffset, inLength, output, outOffset, outLength, 0);
    }

    public int decode(byte[] input, int inOffset, int inLength, byte[] output, int outOffset, int outLength, int skipInitial) {
        int maxout = 0;
        int count = 0;
        int outputPosition = 0;
        int bytesConverted = 0;
        if (output != null) {
            maxout = Math.min(output.length - outOffset, outLength);
        }
        if (inLength > input.length - inOffset) {
            inLength = input.length - inOffset;
        }
        while (inLength > 0) {
            int k = 0;
            int val = 0;
            while (k < 4 && inLength-- > 0) {
                byte cval;
                if ((cval = base64DecodeTable[input[inOffset++] & 127]) < 64) {
                    val = (val << 6) + cval;
                    ++k;
                    continue;
                }
                if (cval != 64 || k == 0) continue;
                inLength = 0;
                break;
            }
            switch (k) {
                case 1: {
                    val <<= 6;
                }
                case 2: {
                    val <<= 6;
                }
                case 3: {
                    val <<= 6;
                }
            }
            if (k >= 1) {
                if (maxout > 0 && bytesConverted >= skipInitial) {
                    --maxout;
                    ++count;
                    output[outOffset + outputPosition++] = (byte)(val >> 16);
                }
                ++bytesConverted;
            }
            if (k >= 3) {
                if (maxout > 0 && bytesConverted >= skipInitial) {
                    --maxout;
                    ++count;
                    output[outOffset + outputPosition++] = (byte)(val >> 8);
                }
                ++bytesConverted;
            }
            if (k != 4) continue;
            if (maxout > 0 && bytesConverted >= skipInitial) {
                --maxout;
                ++count;
                output[outOffset + outputPosition++] = (byte)val;
            }
            ++bytesConverted;
        }
        return count;
    }

    public int encode(byte[] input, int inOffset, int length, byte[] output, int outOffset) {
        return this.encode(input, inOffset, length, output, outOffset, 0);
    }

    public int encode(byte[] input, int inOffset, int length, byte[] output, int outOffset, int effectiveOffset) {
        byte[] ending;
        int val;
        int i;
        int maxout = 0;
        int count = 0;
        if (output != null) {
            maxout = output.length - outOffset;
        }
        if (length > input.length - inOffset) {
            length = input.length - inOffset;
        }
        int inline = effectiveOffset % this.lineLength;
        while (length >= 3) {
            if (inline == this.lineLength) {
                ending = this.lineEnd.getEnding();
                for (i = 0; i < ending.length; ++i) {
                    if (maxout-- <= 0) continue;
                    output[outOffset++] = ending[i];
                    ++count;
                }
                inline = 0;
            }
            val = (input[inOffset++] & 255) << 16;
            val += (input[inOffset++] & 255) << 8;
            val += input[inOffset++] & 255;
            if (maxout-- > 0) {
                output[outOffset++] = base64EncodeTable[val >>> 18];
            }
            if (maxout-- > 0) {
                output[outOffset++] = base64EncodeTable[val >>> 12 & 63];
            }
            if (maxout-- > 0) {
                output[outOffset++] = base64EncodeTable[val >>> 6 & 63];
            }
            if (maxout-- > 0) {
                output[outOffset++] = base64EncodeTable[val & 63];
            }
            length -= 3;
            count += 4;
            inline += 4;
        }
        if ((length > 0 || this.lineEndsAtBreaks) && inline == this.lineLength) {
            ending = this.lineEnd.getEnding();
            for (i = 0; i < ending.length; ++i) {
                if (maxout-- <= 0) continue;
                output[outOffset++] = ending[i];
                ++count;
            }
            inline = 0;
        }
        if (length > 0) {
            val = (input[inOffset++] & 255) << 16;
            if (length > 1) {
                val += (input[inOffset] & 255) << 8;
            }
            if (maxout-- > 0) {
                output[outOffset++] = base64EncodeTable[val >>> 18];
            }
            if (maxout-- > 0) {
                output[outOffset++] = base64EncodeTable[val >>> 12 & 63];
            }
            if (maxout-- > 0) {
                output[outOffset++] = length > 1 ? base64EncodeTable[val >>> 6 & 63] : 61;
            }
            if (maxout-- > 0) {
                output[outOffset++] = 61;
            }
            count += 4;
        }
        return count;
    }

    public char[] encode(byte[] input, int inOffset, int length) {
        int val;
        char[] output = new char[(length * 8 + 23) / 24 * 4];
        int outOffset = 0;
        while (length >= 3) {
            val = (input[inOffset++] & 255) << 16;
            val |= (input[inOffset++] & 255) << 8;
            output[outOffset++] = bitsToChar[(val |= input[inOffset++] & 255) >>> 18 & 63];
            output[outOffset++] = bitsToChar[val >>> 12 & 63];
            output[outOffset++] = bitsToChar[val >>> 6 & 63];
            output[outOffset++] = bitsToChar[val & 63];
            length -= 3;
        }
        if (length > 0) {
            val = (input[inOffset++] & 255) << 16;
            if (length > 1) {
                val |= (input[inOffset] & 255) << 8;
            }
            output[outOffset++] = bitsToChar[val >>> 18 & 63];
            output[outOffset++] = bitsToChar[val >>> 12 & 63];
            output[outOffset++] = length > 1 ? bitsToChar[val >>> 6 & 63] : 61;
            output[outOffset++] = 61;
        }
        return output;
    }

    public byte[] decode(String s) {
        int inLen = s.length();
        if (inLen % 4 != 0) {
            return null;
        }
        int outLen = 3 * inLen / 4;
        if (inLen > 0 && s.charAt(inLen - 1) == '=') {
            --inLen;
            --outLen;
        }
        if (inLen > 0 && s.charAt(inLen - 1) == '=') {
            --inLen;
            --outLen;
        }
        byte[] bytes = new byte[outLen];
        int b = 0;
        int i = 0;
        while (i < inLen) {
            char c;
            if ((c = s.charAt(i++)) > charToBits.length) {
                return null;
            }
            byte d0 = charToBits[c];
            if ((c = s.charAt(i++)) > charToBits.length) {
                return null;
            }
            byte d1 = charToBits[c];
            int d2 = 0;
            if (i < inLen) {
                if ((c = s.charAt(i++)) > charToBits.length) {
                    return null;
                }
                d2 = charToBits[c];
            }
            int d3 = 0;
            if (i < inLen) {
                if ((c = s.charAt(i++)) > charToBits.length) {
                    return null;
                }
                d3 = charToBits[c];
            }
            if (d0 < 0 || d1 < 0 || d2 < 0 || d3 < 0) {
                return null;
            }
            bytes[b++] = (byte)((d0 & 63) << 2 | (d1 & 48) >> 4);
            if (b >= outLen) continue;
            bytes[b++] = (byte)((d1 & 15) << 4 | (d2 & 60) >> 2);
            if (b >= outLen) continue;
            bytes[b++] = (byte)((d2 & 3) << 6 | d3 & 63);
        }
        return bytes;
    }

    static {
        int i;
        base64DecodeTable = new byte[128];
        base64EncodeTable = new byte[64];
        for (i = 0; i < 128; ++i) {
            Base64Engine.base64DecodeTable[i] = 65;
        }
        for (i = 0; i < 26; ++i) {
            Base64Engine.base64DecodeTable[65 + i] = (byte)i;
            Base64Engine.base64EncodeTable[i] = (byte)(65 + i);
            Base64Engine.base64DecodeTable[97 + i] = (byte)(i + 26);
            Base64Engine.base64EncodeTable[i + 26] = (byte)(97 + i);
        }
        for (i = 0; i < 10; ++i) {
            Base64Engine.base64DecodeTable[48 + i] = (byte)(i + 52);
            Base64Engine.base64EncodeTable[i + 52] = (byte)(48 + i);
        }
        Base64Engine.base64DecodeTable[43] = 62;
        Base64Engine.base64EncodeTable[62] = 43;
        Base64Engine.base64DecodeTable[47] = 63;
        Base64Engine.base64EncodeTable[63] = 47;
        Base64Engine.base64DecodeTable[61] = 64;
        bitsToChar = new char[]{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
        charToBits = new byte[]{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1};
    }

    public static final class LineEnding {
        private byte[] ending;
        private static final byte[] lf = new byte[]{10};
        public static final LineEnding LF = new LineEnding(lf);
        private static final byte[] cr = new byte[]{13};
        public static final LineEnding CR = new LineEnding(cr);
        private static final byte[] crlf = new byte[]{13, 10};
        public static final LineEnding CRLF = new LineEnding(crlf);
        private static final byte[] none = new byte[0];
        public static final LineEnding NONE = new LineEnding(none);

        private LineEnding(byte[] ending) {
            this.ending = ending;
        }

        protected byte[] getEnding() {
            return this.ending;
        }

        protected int length() {
            return this.ending.length;
        }
    }

}