diff --git a/CHANGELOG.md b/CHANGELOG.md
index 469cfb88e..70f423188 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,7 +9,8 @@
* 【json 】 【可能兼容问题】修改JSONObject结构,继承自MapWrapper
* 【core 】 【可能兼容问题】BeanCopier重构,新建XXXCopier,删除XXXValueProvider
* 【core 】 【可能兼容问题】URLEncoder废弃,URLEncoderUtil使用RFC3986
-* 【core 】 【可能兼容问题】增加Base32.encode不足位数补=
+* 【core 】 【可能兼容问题】Base32分离编码和解码,以便减少数据加载,支持Hex模式
+* 【core 】 【不兼容问题】PunyCode参数由String改为Charsequence
### 🐣新特性
* 【http 】 HttpRequest.form采用TableMap方式(issue#I4W427@Gitee)
diff --git a/hutool-core/src/main/java/cn/hutool/core/codec/Base32.java b/hutool-core/src/main/java/cn/hutool/core/codec/Base32.java
index 1fa7db4cb..80c87b7e3 100644
--- a/hutool-core/src/main/java/cn/hutool/core/codec/Base32.java
+++ b/hutool-core/src/main/java/cn/hutool/core/codec/Base32.java
@@ -6,85 +6,28 @@ import cn.hutool.core.util.StrUtil;
import java.nio.charset.Charset;
/**
- * Base32 - encodes and decodes RFC3548 Base32 (see http://www.faqs.org/rfcs/rfc3548.html )
+ * Base32 - encodes and decodes RFC4648 Base32 (see https://datatracker.ietf.org/doc/html/rfc4648#section-6 )
* base32就是用32(2的5次方)个特定ASCII码来表示256个ASCII码。
- * 所以,5个ASCII字符经过base32编码后会变为8个字符(公约数为40),长度增加3/5.不足8n用“=”补足。
- * see http://blog.csdn.net/earbao/article/details/44453937
- * @author Looly
+ * 所以,5个ASCII字符经过base32编码后会变为8个字符(公约数为40),长度增加3/5.不足8n用“=”补足。
+ * 根据RFC4648 Base32规范,支持两种模式:
+ *
+ * - Base 32 Alphabet (ABCDEFGHIJKLMNOPQRSTUVWXYZ234567)
+ * - "Extended Hex" Base 32 Alphabet (0123456789ABCDEFGHIJKLMNOPQRSTUV)
+ *
*
+ * @author Looly
*/
public class Base32 {
-
- private Base32() {}
-
- private static final String BASE32_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
- private static final int[] BASE32_LOOKUP = {//
- 0xFF, 0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, // '0', '1', '2', '3', '4', '5', '6', '7'
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // '8', '9', ':', ';', '<', '=', '>', '?'
- 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G'
- 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, // 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O'
- 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, // 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W'
- 0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 'X', 'Y', 'Z', '[', '\', ']', '^', '_'
- 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g'
- 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, // 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o'
- 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, // 'p', 'q', 'r', 's', 't', 'u', 'v', 'w'
- 0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF // 'x', 'y', 'z', '{', '|', '}', '~', 'DEL'
- };
- private static final int[] BASE32_FILL = {-1, 4, 1, 6, 3};
-
//----------------------------------------------------------------------------------------- encode
+
/**
* 编码
+ *
* @param bytes 数据
* @return base32
*/
public static String encode(final byte[] bytes) {
- int i = 0;
- int index = 0;
- int digit;
- int currByte;
- int nextByte;
-
- int encodeLen = bytes.length * 8 / 5;
- if (encodeLen != 0) {
- encodeLen = encodeLen + 1 + BASE32_FILL[(bytes.length * 8) % 5];
- }
-
- StringBuilder base32 = new StringBuilder(encodeLen);
-
- while (i < bytes.length) {
- // unsign
- currByte = (bytes[i] >= 0) ? bytes[i] : (bytes[i] + 256);
-
- /* Is the current digit going to span a byte boundary? */
- if (index > 3) {
- if ((i + 1) < bytes.length) {
- nextByte = (bytes[i + 1] >= 0) ? bytes[i + 1] : (bytes[i + 1] + 256);
- } else {
- nextByte = 0;
- }
-
- digit = currByte & (0xFF >> index);
- index = (index + 5) % 8;
- digit <<= index;
- digit |= nextByte >> (8 - index);
- i++;
- } else {
- digit = (currByte >> (8 - (index + 5))) & 0x1F;
- index = (index + 5) % 8;
- if (index == 0) {
- i++;
- }
- }
- base32.append(BASE32_CHARS.charAt(digit));
- }
-
- // 末尾补充不足长度的
- while(base32.length() < encodeLen){
- base32.append('=');
- }
-
- return base32.toString();
+ return Base32Codec.INSTANCE.encode(bytes);
}
/**
@@ -100,18 +43,7 @@ public class Base32 {
/**
* base32编码
*
- * @param source 被编码的base32字符串
- * @param charset 字符集
- * @return 被加密后的字符串
- */
- public static String encode(String source, String charset) {
- return encode(StrUtil.bytes(source, charset));
- }
-
- /**
- * base32编码
- *
- * @param source 被编码的base32字符串
+ * @param source 被编码的base32字符串
* @param charset 字符集
* @return 被加密后的字符串
*/
@@ -119,55 +51,47 @@ public class Base32 {
return encode(StrUtil.bytes(source, charset));
}
+ /**
+ * 编码
+ *
+ * @param bytes 数据(Hex模式)
+ * @return base32
+ */
+ public static String encodeHex(final byte[] bytes) {
+ return Base32Codec.INSTANCE.encode(bytes, true);
+ }
+
+ /**
+ * base32编码(Hex模式)
+ *
+ * @param source 被编码的base32字符串
+ * @return 被加密后的字符串
+ */
+ public static String encodeHex(String source) {
+ return encodeHex(source, CharsetUtil.CHARSET_UTF_8);
+ }
+
+ /**
+ * base32编码(Hex模式)
+ *
+ * @param source 被编码的base32字符串
+ * @param charset 字符集
+ * @return 被加密后的字符串
+ */
+ public static String encodeHex(String source, Charset charset) {
+ return encodeHex(StrUtil.bytes(source, charset));
+ }
+
//----------------------------------------------------------------------------------------- decode
+
/**
* 解码
+ *
* @param base32 base32编码
* @return 数据
*/
- public static byte[] decode(final String base32) {
- int i, index, lookup, offset, digit;
- int len = base32.endsWith("=") ? base32.indexOf("=") * 5 / 8 : base32.length() * 5 / 8;
- byte[] bytes = new byte[len];
-
- for (i = 0, index = 0, offset = 0; i < base32.length(); i++) {
- lookup = base32.charAt(i) - '0';
-
- /* Skip chars outside the lookup table */
- if (lookup < 0 || lookup >= BASE32_LOOKUP.length) {
- continue;
- }
-
- digit = BASE32_LOOKUP[lookup];
-
- /* If this digit is not in the table, ignore it */
- if (digit == 0xFF) {
- continue;
- }
-
- if (index <= 3) {
- index = (index + 5) % 8;
- if (index == 0) {
- bytes[offset] |= digit;
- offset++;
- if (offset >= bytes.length) {
- break;
- }
- } else {
- bytes[offset] |= digit << (8 - index);
- }
- } else {
- index = (index + 5) % 8;
- bytes[offset] |= (digit >>> index);
- offset++;
-
- if (offset >= bytes.length) {
- break;
- }
- bytes[offset] |= digit << (8 - index);
- }
- }
- return bytes;
+ public static byte[] decode(String base32) {
+ return Base32Codec.INSTANCE.decode(base32);
}
/**
@@ -183,22 +107,42 @@ public class Base32 {
/**
* base32解码
*
- * @param source 被解码的base32字符串
- * @param charset 字符集
- * @return 被加密后的字符串
- */
- public static String decodeStr(String source, String charset) {
- return StrUtil.str(decode(source), charset);
- }
-
- /**
- * base32解码
- *
- * @param source 被解码的base32字符串
+ * @param source 被解码的base32字符串
* @param charset 字符集
* @return 被加密后的字符串
*/
public static String decodeStr(String source, Charset charset) {
return StrUtil.str(decode(source), charset);
}
+
+ /**
+ * 解码
+ *
+ * @param base32 base32编码
+ * @return 数据
+ */
+ public static byte[] decodeHex(String base32) {
+ return Base32Codec.INSTANCE.decode(base32, true);
+ }
+
+ /**
+ * base32解码
+ *
+ * @param source 被解码的base32字符串
+ * @return 被加密后的字符串
+ */
+ public static String decodeStrHex(String source) {
+ return decodeStrHex(source, CharsetUtil.CHARSET_UTF_8);
+ }
+
+ /**
+ * base32解码
+ *
+ * @param source 被解码的base32字符串
+ * @param charset 字符集
+ * @return 被加密后的字符串
+ */
+ public static String decodeStrHex(String source, Charset charset) {
+ return StrUtil.str(decodeHex(source), charset);
+ }
}
diff --git a/hutool-core/src/main/java/cn/hutool/core/codec/Base32Codec.java b/hutool-core/src/main/java/cn/hutool/core/codec/Base32Codec.java
new file mode 100755
index 000000000..42b926e54
--- /dev/null
+++ b/hutool-core/src/main/java/cn/hutool/core/codec/Base32Codec.java
@@ -0,0 +1,215 @@
+package cn.hutool.core.codec;
+
+import java.util.Arrays;
+
+/**
+ * Base32 - encodes and decodes RFC4648 Base32 (see https://datatracker.ietf.org/doc/html/rfc4648#section-6 )
+ * base32就是用32(2的5次方)个特定ASCII码来表示256个ASCII码。
+ * 所以,5个ASCII字符经过base32编码后会变为8个字符(公约数为40),长度增加3/5.不足8n用“=”补足。
+ * 根据RFC4648 Base32规范,支持两种模式:
+ *
+ * - Base 32 Alphabet (ABCDEFGHIJKLMNOPQRSTUVWXYZ234567)
+ * - "Extended Hex" Base 32 Alphabet (0123456789ABCDEFGHIJKLMNOPQRSTUV)
+ *
+ *
+ * @author Looly
+ * @since 5.8.0
+ */
+public class Base32Codec implements Encoder, Decoder {
+
+ public static Base32Codec INSTANCE = new Base32Codec();
+
+ @Override
+ public String encode(byte[] data) {
+ return encode(data, false);
+ }
+
+ /**
+ * 编码数据
+ *
+ * @param data 数据
+ * @param useHex 是否使用Hex Alphabet
+ * @return 编码后的Base32字符串
+ */
+ public String encode(byte[] data, boolean useHex) {
+ final Base32Encoder encoder = useHex ? Base32Encoder.HEX_ENCODER : Base32Encoder.ENCODER;
+ return encoder.encode(data);
+ }
+
+ @Override
+ public byte[] decode(CharSequence encoded) {
+ return decode(encoded, false);
+ }
+
+ /**
+ * 解码数据
+ *
+ * @param encoded base32字符串
+ * @param useHex 是否使用Hex Alphabet
+ * @return 解码后的内容
+ */
+ public byte[] decode(CharSequence encoded, boolean useHex) {
+ final Base32Decoder decoder = useHex ? Base32Decoder.HEX_DECODER : Base32Decoder.DECODER;
+ return decoder.decode(encoded);
+ }
+
+ /**
+ * Bas32编码器
+ */
+ public static class Base32Encoder implements Encoder {
+ private static final String DEFAULT_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
+ private static final String HEX_ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
+ private static final Character DEFAULT_PAD = '=';
+ private static final int[] BASE32_FILL = {-1, 4, 1, 6, 3};
+
+ public static final Base32Encoder ENCODER = new Base32Encoder(DEFAULT_ALPHABET, DEFAULT_PAD);
+ public static final Base32Encoder HEX_ENCODER = new Base32Encoder(HEX_ALPHABET, DEFAULT_PAD);
+
+ private final char[] alphabet;
+ private final Character pad;
+
+ /**
+ * 构造
+ *
+ * @param alphabet 自定义编码字母表,见 {@link #DEFAULT_ALPHABET}和 {@link #HEX_ALPHABET}
+ * @param pad 补位字符
+ */
+ public Base32Encoder(String alphabet, Character pad) {
+ this.alphabet = alphabet.toCharArray();
+ this.pad = pad;
+ }
+
+ @Override
+ public String encode(byte[] data) {
+ int i = 0;
+ int index = 0;
+ int digit;
+ int currByte;
+ int nextByte;
+
+ int encodeLen = data.length * 8 / 5;
+ if (encodeLen != 0) {
+ encodeLen = encodeLen + 1 + BASE32_FILL[(data.length * 8) % 5];
+ }
+
+ StringBuilder base32 = new StringBuilder(encodeLen);
+
+ while (i < data.length) {
+ // unsign
+ currByte = (data[i] >= 0) ? data[i] : (data[i] + 256);
+
+ /* Is the current digit going to span a byte boundary? */
+ if (index > 3) {
+ if ((i + 1) < data.length) {
+ nextByte = (data[i + 1] >= 0) ? data[i + 1] : (data[i + 1] + 256);
+ } else {
+ nextByte = 0;
+ }
+
+ digit = currByte & (0xFF >> index);
+ index = (index + 5) % 8;
+ digit <<= index;
+ digit |= nextByte >> (8 - index);
+ i++;
+ } else {
+ digit = (currByte >> (8 - (index + 5))) & 0x1F;
+ index = (index + 5) % 8;
+ if (index == 0) {
+ i++;
+ }
+ }
+ base32.append(alphabet[digit]);
+ }
+
+ if (null != pad) {
+ // 末尾补充不足长度的
+ while (base32.length() < encodeLen) {
+ base32.append(pad.charValue());
+ }
+ }
+
+ return base32.toString();
+ }
+ }
+
+ /**
+ * Base32解码器
+ */
+ public static class Base32Decoder implements Decoder {
+ private static final char BASE_CHAR = '0';
+
+ public static final Base32Decoder DECODER = new Base32Decoder(Base32Encoder.DEFAULT_ALPHABET);
+ public static final Base32Decoder HEX_DECODER = new Base32Decoder(Base32Encoder.HEX_ALPHABET);
+
+ private final byte[] lookupTable;
+
+ /**
+ * 构造
+ *
+ * @param alphabet 编码字母表
+ */
+ public Base32Decoder(String alphabet) {
+ lookupTable = new byte[128];
+ Arrays.fill(lookupTable, (byte) -1);
+
+ final int length = alphabet.length();
+
+ char c;
+ for (int i = 0; i < length; i++) {
+ c = alphabet.charAt(i);
+ lookupTable[c - BASE_CHAR] = (byte) i;
+ // 支持小写字母解码
+ if(c >= 'A' && c <= 'Z'){
+ lookupTable[Character.toLowerCase(c) - BASE_CHAR] = (byte) i;
+ }
+ }
+ }
+
+ @Override
+ public byte[] decode(CharSequence encoded) {
+ int i, index, lookup, offset, digit;
+ final String base32 = encoded.toString();
+ int len = base32.endsWith("=") ? base32.indexOf("=") * 5 / 8 : base32.length() * 5 / 8;
+ byte[] bytes = new byte[len];
+
+ for (i = 0, index = 0, offset = 0; i < base32.length(); i++) {
+ lookup = base32.charAt(i) - BASE_CHAR;
+
+ /* Skip chars outside the lookup table */
+ if (lookup < 0 || lookup >= lookupTable.length) {
+ continue;
+ }
+
+ digit = lookupTable[lookup];
+
+ /* If this digit is not in the table, ignore it */
+ if (digit < 0) {
+ continue;
+ }
+
+ if (index <= 3) {
+ index = (index + 5) % 8;
+ if (index == 0) {
+ bytes[offset] |= digit;
+ offset++;
+ if (offset >= bytes.length) {
+ break;
+ }
+ } else {
+ bytes[offset] |= digit << (8 - index);
+ }
+ } else {
+ index = (index + 5) % 8;
+ bytes[offset] |= (digit >>> index);
+ offset++;
+
+ if (offset >= bytes.length) {
+ break;
+ }
+ bytes[offset] |= digit << (8 - index);
+ }
+ }
+ return bytes;
+ }
+ }
+}
diff --git a/hutool-core/src/main/java/cn/hutool/core/codec/Base58Codec.java b/hutool-core/src/main/java/cn/hutool/core/codec/Base58Codec.java
index 6e6d02d82..da278731e 100644
--- a/hutool-core/src/main/java/cn/hutool/core/codec/Base58Codec.java
+++ b/hutool-core/src/main/java/cn/hutool/core/codec/Base58Codec.java
@@ -15,10 +15,6 @@ public class Base58Codec implements Encoder, Decoder, Decoder= 0) {
- encoded[--outputStart] = ENCODED_ZERO;
- }
- // Return encoded string (including encoded leading zeros).
- return new String(encoded, outputStart, encoded.length - outputStart);
+ return Base58Encoder.ENCODER.encode(data);
}
/**
@@ -68,52 +35,130 @@ public class Base58Codec implements Encoder, Decoder {
+ private static final String DEFAULT_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
+
+ public static final Base58Encoder ENCODER = new Base58Encoder(DEFAULT_ALPHABET.toCharArray());
+
+ private final char[] alphabet;
+ private final char alphabetZero;
+
+ /**
+ * 构造
+ *
+ * @param alphabet 编码字母表
+ */
+ public Base58Encoder(char[] alphabet) {
+ this.alphabet = alphabet;
+ alphabetZero = alphabet[0];
+ }
+
+ @Override
+ public String encode(byte[] data) {
+ if (null == data) {
+ return null;
+ }
+ if (data.length == 0) {
+ return StrUtil.EMPTY;
+ }
+ // 计算开头0的个数
+ int zeroCount = 0;
+ while (zeroCount < data.length && data[zeroCount] == 0) {
+ ++zeroCount;
+ }
+ // 将256位编码转换为58位编码
+ data = Arrays.copyOf(data, data.length); // since we modify it in-place
+ final char[] encoded = new char[data.length * 2]; // upper bound
+ int outputStart = encoded.length;
+ for (int inputStart = zeroCount; inputStart < data.length; ) {
+ encoded[--outputStart] = alphabet[divmod(data, inputStart, 256, 58)];
+ if (data[inputStart] == 0) {
+ ++inputStart; // optimization - skip leading zeros
+ }
+ }
+ // Preserve exactly as many leading encoded zeros in output as there were leading zeros in input.
+ while (outputStart < encoded.length && encoded[outputStart] == alphabetZero) {
+ ++outputStart;
+ }
+ while (--zeroCount >= 0) {
+ encoded[--outputStart] = alphabetZero;
+ }
+ // Return encoded string (including encoded leading zeros).
+ return new String(encoded, outputStart, encoded.length - outputStart);
+ }
+ }
+
+ /**
+ * Base58解码器
+ *
+ * @since 5.8.0
+ */
+ public static class Base58Decoder implements Decoder {
+
+ public static Base58Decoder DECODER = new Base58Decoder(Base58Encoder.DEFAULT_ALPHABET);
+
+ private final byte[] lookupTable;
+
+ /**
+ * 构造
+ *
+ * @param alphabet 编码字符表
+ */
+ public Base58Decoder(String alphabet) {
+ final byte[] lookupTable = new byte['z' + 1];
+ Arrays.fill(lookupTable, (byte) -1);
+
+ final int length = alphabet.length();
+ for (int i = 0; i < length; i++) {
+ lookupTable[alphabet.charAt(i)] = (byte) i;
+ }
+ this.lookupTable = lookupTable;
+ }
+
+ @Override
+ public byte[] decode(CharSequence encoded) {
+ if (encoded.length() == 0) {
+ return new byte[0];
+ }
+ // Convert the base58-encoded ASCII chars to a base58 byte sequence (base58 digits).
+ final byte[] input58 = new byte[encoded.length()];
+ for (int i = 0; i < encoded.length(); ++i) {
+ char c = encoded.charAt(i);
+ int digit = c < 128 ? lookupTable[c] : -1;
+ if (digit < 0) {
+ throw new IllegalArgumentException(StrUtil.format("Invalid char '{}' at [{}]", c, i));
+ }
+ input58[i] = (byte) digit;
+ }
+ // Count leading zeros.
+ int zeros = 0;
+ while (zeros < input58.length && input58[zeros] == 0) {
+ ++zeros;
+ }
+ // Convert base-58 digits to base-256 digits.
+ byte[] decoded = new byte[encoded.length()];
+ int outputStart = decoded.length;
+ for (int inputStart = zeros; inputStart < input58.length; ) {
+ decoded[--outputStart] = divmod(input58, inputStart, 58, 256);
+ if (input58[inputStart] == 0) {
+ ++inputStart; // optimization - skip leading zeros
+ }
+ }
+ // Ignore extra leading zeroes that were added during the calculation.
+ while (outputStart < decoded.length && decoded[outputStart] == 0) {
+ ++outputStart;
+ }
+ // Return decoded data (including original number of leading zeros).
+ return Arrays.copyOfRange(decoded, outputStart - zeros, decoded.length);
+ }
}
/**
diff --git a/hutool-core/src/main/java/cn/hutool/core/codec/Base64Decoder.java b/hutool-core/src/main/java/cn/hutool/core/codec/Base64Decoder.java
index 20d0baad9..92b95cb33 100644
--- a/hutool-core/src/main/java/cn/hutool/core/codec/Base64Decoder.java
+++ b/hutool-core/src/main/java/cn/hutool/core/codec/Base64Decoder.java
@@ -1,5 +1,6 @@
package cn.hutool.core.codec;
+import cn.hutool.core.lang.mutable.MutableInt;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
@@ -87,7 +88,7 @@ public class Base64Decoder {
return in;
}
- final IntWrapper offset = new IntWrapper(pos);
+ final MutableInt offset = new MutableInt(pos);
byte sestet0;
byte sestet1;
@@ -96,7 +97,7 @@ public class Base64Decoder {
int maxPos = pos + length - 1;
int octetId = 0;
byte[] octet = new byte[length * 3 / 4];// over-estimated if non-base64 characters present
- while (offset.value <= maxPos) {
+ while (offset.intValue() <= maxPos) {
sestet0 = getNextValidDecodeByte(in, offset, maxPos);
sestet1 = getNextValidDecodeByte(in, offset, maxPos);
sestet2 = getNextValidDecodeByte(in, offset, maxPos);
@@ -141,11 +142,12 @@ public class Base64Decoder {
* @param maxPos 最大位置
* @return 有效字符,如果达到末尾返回
*/
- private static byte getNextValidDecodeByte(byte[] in, IntWrapper pos, int maxPos) {
+ private static byte getNextValidDecodeByte(byte[] in, MutableInt pos, int maxPos) {
byte base64Byte;
byte decodeByte;
- while (pos.value <= maxPos) {
- base64Byte = in[pos.value++];
+ while (pos.intValue() <= maxPos) {
+ base64Byte = in[pos.intValue()];
+ pos.increment();
if (base64Byte > -1) {
decodeByte = DECODE_TABLE[base64Byte];
if (decodeByte > -1) {
@@ -156,19 +158,5 @@ public class Base64Decoder {
// padding if reached max position
return PADDING;
}
-
- /**
- * int包装,使之可变
- *
- * @author looly
- *
- */
- private static class IntWrapper {
- int value;
-
- IntWrapper(int value) {
- this.value = value;
- }
- }
// ----------------------------------------------------------------------------------------------- Private end
}
diff --git a/hutool-core/src/main/java/cn/hutool/core/codec/PunyCode.java b/hutool-core/src/main/java/cn/hutool/core/codec/PunyCode.java
index d49a046c4..fd3fc3864 100644
--- a/hutool-core/src/main/java/cn/hutool/core/codec/PunyCode.java
+++ b/hutool-core/src/main/java/cn/hutool/core/codec/PunyCode.java
@@ -27,11 +27,11 @@ public class PunyCode {
/**
* 将内容编码为PunyCode
*
- * @param input 字符串
+ * @param input 字符串
* @return PunyCode字符串
* @throws UtilException 计算异常
*/
- public static String encode(String input) throws UtilException {
+ public static String encode(CharSequence input) throws UtilException {
return encode(input, false);
}
@@ -43,7 +43,7 @@ public class PunyCode {
* @return PunyCode字符串
* @throws UtilException 计算异常
*/
- public static String encode(String input, boolean withPrefix) throws UtilException {
+ public static String encode(CharSequence input, boolean withPrefix) throws UtilException {
int n = INITIAL_N;
int delta = 0;
int bias = INITIAL_BIAS;
@@ -112,7 +112,7 @@ public class PunyCode {
n++;
}
- if(withPrefix){
+ if (withPrefix) {
output.insert(0, PUNY_CODE_PREFIX);
}
return output.toString();
@@ -214,6 +214,7 @@ public class PunyCode {
* ...
* 35 -> '9'
*
+ *
* @param d 输入字符
* @return 转换后的字符
* @throws UtilException 无效字符
@@ -242,6 +243,7 @@ public class PunyCode {
* ...
* '9' -> 35
*
+ *
* @param c 输入字符
* @return 转换后的字符
* @throws UtilException 无效字符
diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/mutable/MutableInt.java b/hutool-core/src/main/java/cn/hutool/core/lang/mutable/MutableInt.java
index dce1dd9fc..ae033437f 100644
--- a/hutool-core/src/main/java/cn/hutool/core/lang/mutable/MutableInt.java
+++ b/hutool-core/src/main/java/cn/hutool/core/lang/mutable/MutableInt.java
@@ -152,12 +152,12 @@ public class MutableInt extends Number implements Comparable, Mutabl
* 相等需同时满足如下条件:
*
* - 非空
- * - 类型为 {@link MutableInt}
+ * - 类型为 MutableInt
* - 值相等
*
*
* @param obj 比对的对象
- * @return 相同返回true
,否则 false
+ * @return 相同返回true
,否则 {@code false}
*/
@Override
public boolean equals(final Object obj) {
@@ -176,7 +176,7 @@ public class MutableInt extends Number implements Comparable, Mutabl
/**
* 比较
*
- * @param other 其它 {@link MutableInt} 对象
+ * @param other 其它 MutableInt 对象
* @return x==y返回0,x<y返回-1,x>y返回1
*/
@Override
diff --git a/hutool-core/src/test/java/cn/hutool/core/codec/Base32Test.java b/hutool-core/src/test/java/cn/hutool/core/codec/Base32Test.java
index a17f2e4ab..5d74654bf 100644
--- a/hutool-core/src/test/java/cn/hutool/core/codec/Base32Test.java
+++ b/hutool-core/src/test/java/cn/hutool/core/codec/Base32Test.java
@@ -1,6 +1,7 @@
package cn.hutool.core.codec;
import cn.hutool.core.util.RandomUtil;
+import cn.hutool.core.util.StrUtil;
import org.junit.Assert;
import org.junit.Test;
@@ -14,6 +15,24 @@ public class Base32Test {
String decodeStr = Base32.decodeStr(encode);
Assert.assertEquals(a, decodeStr);
+
+ // 支持小写模式解码
+ decodeStr = Base32.decodeStr(encode.toLowerCase());
+ Assert.assertEquals(a, decodeStr);
+ }
+
+ @Test
+ public void hexEncodeAndDecodeTest(){
+ String a = "伦家是一个非常长的字符串";
+ String encode = Base32.encodeHex(StrUtil.utf8Bytes(a));
+ Assert.assertEquals("SIUADPDEMRJ9HBV4N20E9E5AT6EPTPDON3KPBFV7JA2EBBCNSUMADP5OM8======", encode);
+
+ String decodeStr = Base32.decodeStrHex(encode);
+ Assert.assertEquals(a, decodeStr);
+
+ // 支持小写模式解码
+ decodeStr = Base32.decodeStrHex(encode.toLowerCase());
+ Assert.assertEquals(a, decodeStr);
}
@Test