shz.Coder Maven / Gradle / Ivy
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