支持自定义查找表的Base64算法

有时候需要自定义base64算法的查找表

package com.cyao.util;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * 支持自定义查找表的Base64算法
 *
 * @author Cyao
 */
public class Base64Enhanced {
    public static final Base64Enhanced INSTANCE = new Base64Enhanced();

    private final char[] chars;

    private final int[] INV = new int[256];

    public Base64Enhanced() {
        this("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
    }

    public Base64Enhanced(String chars) {
        this.chars = chars.toCharArray();
        Arrays.fill(INV, -1);
        for (int i = 0, length = this.chars.length; i < length; i++) {
            INV[this.chars[i]] = i;
        }
        INV['='] = 0;
    }

    /**
     * 生成查找表
     *
     * @return
     */
    public static String generate() {
        List<String> list = new ArrayList<>();
        for (char c : INSTANCE.chars) {
            list.add(String.valueOf(c));
        }
        Collections.shuffle(list);
        return String.join("", list);
    }

    /**
     * 对字符串进行编码
     *
     * @param str 源字符串
     * @return 编码后字符串
     */
    public String encode(String str) {
        return encode(str, "UTF-8");
    }

    /**
     * 对字符串进行编码
     *
     * @param str         源字符串
     * @param charsetName 字符集名称
     * @return 编码后字符串
     */
    public String encode(String str, String charsetName) {
        byte[] bytes = str.getBytes(Charset.forName(charsetName));
        return new String(encode(bytes), StandardCharsets.US_ASCII);
    }

    /**
     * 对字符串进行解码
     *
     * @param str 编码后字符串
     * @return 解码后的字符串
     */
    public String decode(String str) {
        return decode(str, "UTF-8");
    }

    /**
     * 对字符串进行解码
     *
     * @param str         编码后字符串
     * @param charsetName 字符集名称
     * @return 解码后的字符串
     */
    public String decode(String str, String charsetName) {
        byte[] bytes = str.getBytes(StandardCharsets.US_ASCII);
        return new String(decode(bytes), Charset.forName(charsetName));
    }

    /**
     * 对字节流进行编码
     *
     * @param bytes 源字节流
     * @return 编码后字节流
     */
    public byte[] encode(final byte[] bytes) {
        int len = bytes != null ? bytes.length : 0;

        if (len == 0) {
            return new byte[0];
        }

        int evenlen = (len / 3) * 3;

        int cnt = ((len - 1) / 3 + 1) << 2;

        byte[] dest = new byte[cnt];

        for (int s = 0, d = 0, cc = 0; s < evenlen; ) {
            int i = (bytes[s++] & 0xff) << 16 | (bytes[s++] & 0xff) << 8 | (bytes[s++] & 0xff);
            dest[d++] = (byte) chars[(i >>> 18) & 0x3f];
            dest[d++] = (byte) chars[(i >>> 12) & 0x3f];
            dest[d++] = (byte) chars[(i >>> 6) & 0x3f];
            dest[d++] = (byte) chars[i & 0x3f];
        }

        int left = len - evenlen;
        if (left > 0) {
            int i = ((bytes[evenlen] & 0xff) << 10) | (left == 2 ? ((bytes[len - 1] & 0xff) << 2) : 0);
            dest[cnt - 4] = (byte) chars[i >> 12];
            dest[cnt - 3] = (byte) chars[(i >>> 6) & 0x3f];
            dest[cnt - 2] = left == 2 ? (byte) chars[i & 0x3f] : (byte) '=';
            dest[cnt - 1] = '=';
        }

        return dest;
    }

    /**
     * 对字节流进行解码
     *
     * @param bytes 源字节流
     * @return 解码后字节流
     */
    public byte[] decode(final byte[] bytes) {
        int length = bytes.length;

        if (length == 0) {
            return new byte[0];
        }

        int sndx = 0, endx = length - 1;
        int pad = bytes[endx] == '=' ? (bytes[endx - 1] == '=' ? 2 : 1) : 0;
        int cnt = endx - sndx + 1;
        int sepCnt = length > 76 ? (bytes[76] == '\r' ? cnt / 78 : 0) << 1 : 0;
        int len = ((cnt - sepCnt) * 6 >> 3) - pad;
        byte[] dest = new byte[len];

        int d = 0;
        for (int cc = 0, eLen = (len / 3) * 3; d < eLen; ) {
            int i = INV[bytes[sndx++]] << 18 | INV[bytes[sndx++]] << 12 | INV[bytes[sndx++]] << 6 | INV[bytes[sndx++]];
            dest[d++] = (byte) (i >> 16);
            dest[d++] = (byte) (i >> 8);
            dest[d++] = (byte) i;
            if (sepCnt > 0 && ++cc == 19) {
                sndx += 2;
                cc = 0;
            }
        }

        if (d < len) {
            int i = 0;
            for (int j = 0; sndx <= endx - pad; j++) {
                i |= INV[bytes[sndx++]] << (18 - j * 6);
            }
            for (int r = 16; d < len; r -= 8) {
                dest[d++] = (byte) (i >> r);
            }
        }

        return dest;
    }
}
@Test
public void testBase64() {
    String str = "中文字符";

    String chars = Base64Enhanced.generate();

    System.out.println("generateChars:" + chars);

    Base64Enhanced base64Enhanced = new Base64Enhanced(chars);

    System.out.println(base64Enhanced.encode(str));

    System.out.println(base64Enhanced.decode(base64Enhanced.encode(str)));
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

漠星曜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值