diff --git a/CHANGELOG.md b/CHANGELOG.md index c2ddb1051..0fd6372e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ------------------------------------------------------------------------------------------------------------- -# 5.5.2 (2020-11-26) +# 5.5.2 (2020-12-01) ### 新特性 * 【crypto 】 KeyUtil增加重载,AES构造增加重载(issue#I25NNZ@Gitee) @@ -28,6 +28,7 @@ * 【core 】 修改IoUtil.read(Reader)逻辑默认关闭Reader * 【core 】 ZipUtil增加Zip方法(pr#222@Gitee) * 【all 】 增加Hutool.getAllUtils和printAllUtils方法 +* 【all 】 增加PonyCode(issue#1268@Gitee) ### Bug修复 * 【cron 】 修复CronTimer可能死循环的问题(issue#1224@Github) @@ -36,6 +37,7 @@ * 【core 】 修复HexUtil.format问题(issue#I268XT@Gitee) * 【core 】 修复ZipUtil判断压缩文件是否位于压缩目录内的逻辑有误的问题(issue#1251@Github) * 【json 】 修复JSONObject.accumulate问题 +* 【core 】 修复部分xlsx文件sax方式解析空指针问题(issue#1265@Github) ------------------------------------------------------------------------------------------------------------- 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 new file mode 100644 index 000000000..b2077469b --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/codec/PunyCode.java @@ -0,0 +1,218 @@ +package cn.hutool.core.codec; + +import cn.hutool.core.exceptions.UtilException; +import cn.hutool.core.util.StrUtil; + +/** + * Punycode是一个根据RFC 3492标准而制定的编码系统,主要用于把域名从地方语言所采用的Unicode编码转换成为可用于DNS系统的编码 + *
+ * 参考:https://blog.csdn.net/a19881029/article/details/18262671
+ *
+ * @author looly
+ * @since 5.5.2
+ */
+public class PunyCode {
+ private static final int TMIN = 1;
+ private static final int TMAX = 26;
+ private static final int BASE = 36;
+ private static final int INITIAL_N = 128;
+ private static final int INITIAL_BIAS = 72;
+ private static final int DAMP = 700;
+ private static final int SKEW = 38;
+ private static final char DELIMITER = '-';
+ private static final String PONY_CODE_PREFIX = "xn--";
+
+ /**
+ * Punycodes a unicode string.
+ *
+ * @param input Unicode string.
+ * @return Punycoded string.
+ * @throws UtilException 计算异常
+ */
+ public static String encode(String input) throws UtilException {
+ int n = INITIAL_N;
+ int delta = 0;
+ int bias = INITIAL_BIAS;
+ StringBuilder output = new StringBuilder();
+ // Copy all basic code points to the output
+ int length = input.length();
+ int b = 0;
+ char c;
+ for (int i = 0; i < length; i++) {
+ c = input.charAt(i);
+ if (isBasic(c)) {
+ output.append(c);
+ b++;
+ }
+ }
+ // Append delimiter
+ if (b > 0) {
+ output.append(DELIMITER);
+ }
+ int h = b;
+ while (h < input.length()) {
+ int m = Integer.MAX_VALUE;
+ // Find the minimum code point >= n
+ for (int i = 0; i < input.length(); i++) {
+ int c = input.charAt(i);
+ if (c >= n && c < m) {
+ m = c;
+ }
+ }
+ if (m - n > (Integer.MAX_VALUE - delta) / (h + 1)) {
+ throw new UtilException("OVERFLOW");
+ }
+ delta = delta + (m - n) * (h + 1);
+ n = m;
+ for (int j = 0; j < input.length(); j++) {
+ int c = input.charAt(j);
+ if (c < n) {
+ delta++;
+ if (0 == delta) {
+ throw new UtilException("OVERFLOW");
+ }
+ }
+ if (c == n) {
+ int q = delta;
+ for (int k = BASE; ; k += BASE) {
+ int t;
+ if (k <= bias) {
+ t = TMIN;
+ } else if (k >= bias + TMAX) {
+ t = TMAX;
+ } else {
+ t = k - bias;
+ }
+ if (q < t) {
+ break;
+ }
+ output.append((char) digit2codepoint(t + (q - t)
+ % (BASE - t)));
+ q = (q - t) / (BASE - t);
+ }
+ output.append((char) digit2codepoint(q));
+ bias = adapt(delta, h + 1, h == b);
+ delta = 0;
+ h++;
+ }
+ }
+ delta++;
+ n++;
+ }
+ return output.toString();
+ }
+
+ /**
+ * Decode a punycoded string.
+ *
+ * @param input Punycode string
+ * @return Unicode string.
+ * @throws UtilException 计算异常
+ */
+ public static String decode(String input) throws UtilException {
+ input = StrUtil.removePrefixIgnoreCase(input, PONY_CODE_PREFIX);
+ int n = INITIAL_N;
+ int i = 0;
+ int bias = INITIAL_BIAS;
+ StringBuilder output = new StringBuilder();
+ int d = input.lastIndexOf(DELIMITER);
+ if (d > 0) {
+ for (int j = 0; j < d; j++) {
+ char c = input.charAt(j);
+ if (false == isBasic(c)) {
+ throw new UtilException("BAD_INPUT");
+ }
+ output.append(c);
+ }
+ d++;
+ } else {
+ d = 0;
+ }
+ while (d < input.length()) {
+ int oldi = i;
+ int w = 1;
+ for (int k = BASE; ; k += BASE) {
+ if (d == input.length()) {
+ throw new UtilException("BAD_INPUT");
+ }
+ int c = input.charAt(d++);
+ int digit = codepoint2digit(c);
+ if (digit > (Integer.MAX_VALUE - i) / w) {
+ throw new UtilException("OVERFLOW");
+ }
+ i = i + digit * w;
+ int t;
+ if (k <= bias) {
+ t = TMIN;
+ } else if (k >= bias + TMAX) {
+ t = TMAX;
+ } else {
+ t = k - bias;
+ }
+ if (digit < t) {
+ break;
+ }
+ w = w * (BASE - t);
+ }
+ bias = adapt(i - oldi, output.length() + 1, oldi == 0);
+ if (i / (output.length() + 1) > Integer.MAX_VALUE - n) {
+ throw new UtilException("OVERFLOW");
+ }
+ n = n + i / (output.length() + 1);
+ i = i % (output.length() + 1);
+ output.insert(i, (char) n);
+ i++;
+ }
+ return output.toString();
+ }
+
+ public static int adapt(int delta, int numpoints, boolean first) {
+ if (first) {
+ delta = delta / DAMP;
+ } else {
+ delta = delta / 2;
+ }
+ delta = delta + (delta / numpoints);
+ int k = 0;
+ while (delta > ((BASE - TMIN) * TMAX) / 2) {
+ delta = delta / (BASE - TMIN);
+ k = k + BASE;
+ }
+ return k + ((BASE - TMIN + 1) * delta) / (delta + SKEW);
+ }
+
+ public static boolean isBasic(char c) {
+ return c < 0x80;
+ }
+
+ public static int digit2codepoint(int d) throws UtilException {
+ if (d < 26) {
+ // 0..25 : 'a'..'z'
+ return d + 'a';
+ } else if (d < 36) {
+ // 26..35 : '0'..'9';
+ return d - 26 + '0';
+ } else {
+ throw new UtilException("BAD_INPUT");
+ }
+ }
+
+ public static int codepoint2digit(int c) throws UtilException {
+ if (c - '0' < 10) {
+ // '0'..'9' : 26..35
+ return c - '0' + 26;
+ } else if (c - 'a' < 26) {
+ // 'a'..'z' : 0..25
+ return c - 'a';
+ } else {
+ throw new UtilException("BAD_INPUT");
+ }
+ }
+
+ public static void main(String[] args) {
+ String strPunycode = PONY_CODE_PREFIX + encode("北京大学");
+ System.out.println(strPunycode);
+ String strChinese = decode("xn--1lq90ic7fzpc");
+ System.out.println(strChinese);
+ }
+}
diff --git a/hutool-core/src/main/java/cn/hutool/core/io/watch/WatchMonitor.java b/hutool-core/src/main/java/cn/hutool/core/io/watch/WatchMonitor.java
index daaefe156..09fedf471 100644
--- a/hutool-core/src/main/java/cn/hutool/core/io/watch/WatchMonitor.java
+++ b/hutool-core/src/main/java/cn/hutool/core/io/watch/WatchMonitor.java
@@ -193,7 +193,7 @@ public class WatchMonitor extends WatchServer {
*
* @param uri URI
* @param watcher {@link Watcher}
- * @return {@link WatchMonitor}
+ * @return WatchMonitor
*/
public static WatchMonitor createAll(URI uri, Watcher watcher) {
return createAll(Paths.get(uri), watcher);
@@ -204,7 +204,7 @@ public class WatchMonitor extends WatchServer {
*
* @param url URL
* @param watcher {@link Watcher}
- * @return {@link WatchMonitor}
+ * @return WatchMonitor
*/
public static WatchMonitor createAll(URL url, Watcher watcher) {
try {
@@ -219,7 +219,7 @@ public class WatchMonitor extends WatchServer {
*
* @param file 被监听文件
* @param watcher {@link Watcher}
- * @return {@link WatchMonitor}
+ * @return WatchMonitor
*/
public static WatchMonitor createAll(File file, Watcher watcher) {
return createAll(file.toPath(), watcher);
@@ -230,7 +230,7 @@ public class WatchMonitor extends WatchServer {
*
* @param path 路径
* @param watcher {@link Watcher}
- * @return {@link WatchMonitor}
+ * @return WatchMonitor
*/
public static WatchMonitor createAll(String path, Watcher watcher) {
return createAll(Paths.get(path), watcher);
@@ -241,7 +241,7 @@ public class WatchMonitor extends WatchServer {
*
* @param path 路径
* @param watcher {@link Watcher}
- * @return {@link WatchMonitor}
+ * @return WatchMonitor
*/
public static WatchMonitor createAll(Path path, Watcher watcher) {
final WatchMonitor watchMonitor = create(path, EVENTS_ALL);
@@ -348,7 +348,7 @@ public class WatchMonitor extends WatchServer {
* 多个监听请使用{@link WatcherChain}
*
* @param watcher 监听
- * @return {@link WatchMonitor}
+ * @return WatchMonitor
*/
public WatchMonitor setWatcher(Watcher watcher) {
this.watcher = watcher;
diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/Excel07SaxReader.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/Excel07SaxReader.java
index 46c59ec77..beb254621 100644
--- a/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/Excel07SaxReader.java
+++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/Excel07SaxReader.java
@@ -229,16 +229,20 @@ public class Excel07SaxReader extends DefaultHandler implements ExcelSaxReader