All Downloads are FREE. Search and download functionalities are using the official Maven repository.

shz.Coder Maven / Gradle / Ivy

There is a newer version: 2.0
Show newest version
package shz;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
import java.util.function.Consumer;

/**
 * 编码工具
 */
public final class Coder {
    private Coder() {
        throw new IllegalStateException();
    }

    private static MessageDigest getInstance(String algorithm) {
        try {
            return MessageDigest.getInstance(algorithm);
        } catch (NoSuchAlgorithmException e) {
            throw PRException.of(e);
        }
    }

    /**
     * 哈希运算
     */
    public static byte[] hash(byte[] bytes, String algorithm) {
        MessageDigest instance = getInstance(algorithm);
        instance.update(bytes);
        return instance.digest();
    }

    /**
     * 十六进制编码,拆分高低位
     */
    public static String hexEncode(byte[] bytes) {
        if (Validator.isEmpty(bytes)) return "";
        char[] chars = new char[bytes.length << 1];
        int idx = 0;
        for (byte b : bytes) {
            chars[idx++] = ArrayConstant.ARRAY_16[b >>> 4 & 0xf];
            chars[idx++] = ArrayConstant.ARRAY_16[b & 0xf];
        }
        return new String(chars);
    }

    /**
     * 十六进制解码,组合高低位
     */
    public static byte[] hexDecode(String s) {
        if (Validator.isBlank(s)) return ArrayConstant.EMPTY_BYTE_ARRAY;
        if ((s.length() & 1) != 0) throw new IllegalArgumentException(Help.format("非法十六进制编码,长度%d", s.length()));
        byte[] bytes = new byte[s.length() >>> 1];
        for (int i = 0, h, l; i < s.length(); i += 2) {
            h = Character.digit(s.charAt(i), 16);
            l = Character.digit(s.charAt(i + 1), 16);
            if (h < 0 || l < 0) throw new IllegalArgumentException(Help.format("%d或%d位置出现非法字符", i, i + 1));
            bytes[i >>> 1] = (byte) ((h << 4) | l);
        }
        return bytes;
    }

    public static String md5(byte[] bytes) {
        return hexEncode(hash(bytes, "MD5"));
    }

    public static String sha256(byte[] bytes) {
        return hexEncode(hash(bytes, "SHA-256"));
    }

    public static String hmacSha1(byte[] bytes, byte[] key) {
        SecretKey secretKey = new SecretKeySpec(key, "HmacSHA1");
        Mac mac;
        try {
            mac = Mac.getInstance("HmacSHA1");
            mac.init(secretKey);
        } catch (NoSuchAlgorithmException | InvalidKeyException e) {
            throw PRException.of(e);
        }
        return hexEncode(mac.doFinal(bytes));
    }

    /**
     * 哈希输入流
     */
    public static byte[] hash(InputStream is, String algorithm) {
        MessageDigest instance = getInstance(algorithm);
        IOHelp.read(is, (BiConsumer) (buffer, len) -> instance.update(buffer, 0, len));
        return instance.digest();
    }

    public static String md5(InputStream is) {
        return hexEncode(hash(is, "MD5"));
    }

    public static byte[] hash(File file, String algorithm) {
        return hash(IOHelp.getBis(file), algorithm);
    }

    /**
     * MD5加密文件,可用于文件的判重
     */
    public static String md5(File file) {
        return hexEncode(hash(file, "MD5"));
    }

    /**
     * unicode编码
     */
    public static String unicodeEncode(String s) {
        if (Validator.isBlank(s)) return s;
        StringBuilder sb = new StringBuilder(s.length() * 6);
        String hex;
        for (int i = 0; i < s.length(); ++i) {
            sb.append("\\u");
            hex = Integer.toHexString(s.charAt(i));
            if (hex.length() != 4) if (hex.length() == 2) sb.append("00");
            else if (hex.length() == 1) sb.append("000");
            else sb.append("0");
            sb.append(hex);
        }
        return sb.toString();
    }

    /**
     * unicode解码
     */
    public static String unicodeDecode(String s) {
        if (Validator.isBlank(s)) return s;
        //缓冲区,用来存储已解码字符
        char[] buffer = new char[Math.min(1024, s.length())];
        AtomicInteger bufferOffset = new AtomicInteger();
        char[] array4 = new char[4];
        AtomicInteger array4Offset = new AtomicInteger();
        AtomicReference last = new AtomicReference<>();
        StringBuilder sb = new StringBuilder();
        unicodeDecode0(s, buffer, bufferOffset, array4, array4Offset, last, sb::append);

        //以下是单个字符串处理方法
        //拼接缓冲区剩余的字符
        if (bufferOffset.get() > 0) sb.append(buffer, 0, bufferOffset.get());
        //最后不足四位的字符直接拼接在后面
        if (array4Offset.get() > 0) sb.append(array4, 0, array4Offset.get());
        //存在最后一个无法标识字符
        if (last.get() != null) sb.append(last.get());
        return sb.toString();
    }

    private static void unicodeDecode0(String s, char[] buffer, AtomicInteger bufferOffset,
                                       char[] array4, AtomicInteger array4Offset,
                                       AtomicReference last, Consumer consumer) {
        int len = last.get() == null ? s.length() : s.length() + 1;
        int i = 0;
        if (array4Offset.get() > 0) {
            int min = Math.min(4 - array4Offset.get(), len);
            for (; i < min; ++i) array4[array4Offset.getAndIncrement() + i] = getChar(s, i, last);
            if (array4Offset.get() == 4) {
                addBuffer(buffer, bufferOffset, parseChar(array4), consumer);
                array4Offset.set(0);
            } else {
                last.set(null);
                return;
            }
        }

        for (char cur, next; i < len - 1; ) {
            cur = getChar(s, i, last);
            if (cur != '\\' || ((next = getChar(s, i + 1, last)) != 'u' && next != 'U')) {
                addBuffer(buffer, bufferOffset, cur, consumer);
                ++i;
                continue;
            }
            //跳过\\u
            i += 2;
            int min = Math.min(len, i + 4), mark = i;
            for (; i < min; ++i) array4[i - mark] = getChar(s, i, last);
            if (min < mark + 4) {
                //有效位不足四位,记录偏移量
                array4Offset.set(i - mark);
                break;
            }
            addBuffer(buffer, bufferOffset, parseChar(array4), consumer);
        }
        if (i == len - 1) last.set(getChar(s, i, last));
        else last.set(null);
    }

    /**
     * 这个方法避免直接将last字符拼接在s前面
     */
    private static char getChar(String s, int i, AtomicReference last) {
        if (last.get() == null) return s.charAt(i);
        if (i == 0) return last.get();
        return s.charAt(i - 1);
    }

    private static char parseChar(char[] array4) {
        return (char) Integer.parseInt(new String(array4), 16);
    }

    private static void addBuffer(char[] buffer, AtomicInteger bufferOffset, char c, Consumer consumer) {
        if (bufferOffset.get() == buffer.length) {
            consumer.accept(buffer);
            bufferOffset.set(0);
        }
        buffer[bufferOffset.getAndIncrement()] = c;
    }

    public static String urlEncode(String url, Charset charset) {
        try {
            return URLEncoder.encode(url, charset.name());
        } catch (UnsupportedEncodingException e) {
            throw PRException.of(e);
        }
    }

    public static String urlEncode(String url) {
        return urlEncode(url, StandardCharsets.UTF_8);
    }

    public static String urlDecode(String url, Charset charset) {
        try {
            return URLDecoder.decode(url, charset.name());
        } catch (UnsupportedEncodingException e) {
            throw PRException.of(e);
        }
    }

    public static String urlDecode(String url) {
        return urlDecode(url, StandardCharsets.UTF_8);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy