From 05c5b53c52c711285ec3298abd25178a7dfd640c Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 27 Apr 2025 20:39:49 +0800 Subject: [PATCH] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E6=8E=A2=E6=B5=8B=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E6=96=87=E4=BB=B6=E7=BC=96=E7=A0=81=20(#3863)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/jackhuang/hmcl/game/LogExporter.java | 3 +- HMCLCore/build.gradle.kts | 1 + .../org/jackhuang/hmcl/util/io/IOUtils.java | 29 +++++++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/LogExporter.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/LogExporter.java index 454442c8d..9aed6454f 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/LogExporter.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/LogExporter.java @@ -17,6 +17,7 @@ */ package org.jackhuang.hmcl.game; +import org.jackhuang.hmcl.util.io.IOUtils; import org.jackhuang.hmcl.util.logging.Logger; import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.io.Zipper; @@ -93,7 +94,7 @@ public final class LogExporter { if (Files.isRegularFile(file)) { FileTime time = Files.readAttributes(file, BasicFileAttributes.class).lastModifiedTime(); if (time.toMillis() >= processStartTime) { - try (BufferedReader reader = Files.newBufferedReader(file, OperatingSystem.NATIVE_CHARSET)) { + try (BufferedReader reader = IOUtils.newBufferedReaderMaybeNativeEncoding(file)) { zipper.putLines(reader.lines().map(Logger::filterForbiddenToken), file.getFileName().toString()); } catch (IOException e) { LOG.warning("Failed to read log file: " + file, e); diff --git a/HMCLCore/build.gradle.kts b/HMCLCore/build.gradle.kts index 3952b3f61..f6f26e31b 100644 --- a/HMCLCore/build.gradle.kts +++ b/HMCLCore/build.gradle.kts @@ -16,6 +16,7 @@ dependencies { api("com.github.steveice10:opennbt:1.5") api("org.nanohttpd:nanohttpd:2.3.1") api("org.jsoup:jsoup:1.19.1") + api("org.glavo:chardet:2.5.0") compileOnlyApi("org.jetbrains:annotations:26.0.1") if (JavaVersion.current().isJava8) { diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/IOUtils.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/IOUtils.java index cd2702117..7194e7688 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/IOUtils.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/IOUtils.java @@ -17,10 +17,20 @@ */ package org.jackhuang.hmcl.util.io; +import org.glavo.chardet.DetectedCharset; +import org.glavo.chardet.UniversalDetector; + import java.io.*; +import java.nio.channels.Channels; +import java.nio.channels.FileChannel; import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.zip.GZIPInputStream; +import static java.nio.charset.StandardCharsets.*; +import static org.jackhuang.hmcl.util.platform.OperatingSystem.NATIVE_CHARSET; + /** * This utility class consists of some util methods operating on InputStream/OutputStream. * @@ -33,6 +43,25 @@ public final class IOUtils { public static final int DEFAULT_BUFFER_SIZE = 8 * 1024; + public static BufferedReader newBufferedReaderMaybeNativeEncoding(Path file) throws IOException { + if (NATIVE_CHARSET == UTF_8) + return Files.newBufferedReader(file); + + FileChannel channel = FileChannel.open(file); + try { + long oldPosition = channel.position(); + DetectedCharset detectedCharset = UniversalDetector.detectCharset(channel); + Charset charset = detectedCharset != null && detectedCharset.isSupported() + && (detectedCharset.getCharset() == UTF_8 || detectedCharset.getCharset() == US_ASCII) + ? UTF_8 : NATIVE_CHARSET; + channel.position(oldPosition); + return new BufferedReader(new InputStreamReader(Channels.newInputStream(channel), charset)); + } catch (Throwable e) { + closeQuietly(channel, e); + throw e; + } + } + /** * Read all bytes to a buffer from given input stream. The stream will not be closed. *