diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/MinecraftInstanceTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/MinecraftInstanceTask.java index d4bd61cacf..88d8dc8d03 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/MinecraftInstanceTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/MinecraftInstanceTask.java @@ -17,19 +17,22 @@ */ package org.jackhuang.hmcl.mod; +import kala.compress.archivers.zip.ZipArchiveEntry; import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.util.DigestUtils; import org.jackhuang.hmcl.util.gson.JsonUtils; import org.jackhuang.hmcl.util.io.CompressingUtils; import org.jackhuang.hmcl.util.io.FileUtils; +import org.jackhuang.hmcl.util.tree.ArchiveFileTree; +import org.jackhuang.hmcl.util.tree.ZipFileTree; -import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.nio.charset.Charset; import java.nio.file.*; -import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.List; +import java.util.Map; public final class MinecraftInstanceTask extends Task> { @@ -53,26 +56,42 @@ public MinecraftInstanceTask(Path zipFile, Charset encoding, List subDir this.version = version; } + private static void getOverrides(List overrides, + ZipFileTree tree, + ArchiveFileTree.Dir dir, + List names) throws IOException { + String prefix = String.join("/", names); + if (!prefix.isEmpty()) + prefix = prefix + "/"; + + for (Map.Entry entry : dir.getFiles().entrySet()) { + String hash; + try (InputStream input = tree.getInputStream(entry.getValue())) { + hash = DigestUtils.digestToString("SHA-1", input); + } + overrides.add(new ModpackConfiguration.FileInformation(prefix + entry.getKey(), hash)); + } + + for (ArchiveFileTree.Dir subDir : dir.getSubDirs().values()) { + names.add(subDir.getName()); + getOverrides(overrides, tree, subDir, names); + names.remove(names.size() - 1); + } + } + @Override public void execute() throws Exception { List overrides = new ArrayList<>(); - try (FileSystem fs = CompressingUtils.readonly(zipFile).setEncoding(encoding).build()) { + try (var tree = new ZipFileTree(CompressingUtils.openZipFileWithPossibleEncoding(zipFile, encoding))) { for (String subDirectory : subDirectories) { - Path root = fs.getPath(subDirectory); - - if (Files.exists(root)) - Files.walkFileTree(root, new SimpleFileVisitor<>() { - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - String relativePath = root.relativize(file).normalize().toString().replace(File.separatorChar, '/'); - overrides.add(new ModpackConfiguration.FileInformation(relativePath, DigestUtils.digestToString("SHA-1", file))); - return FileVisitResult.CONTINUE; - } - }); + ArchiveFileTree.Dir root = tree.getDirectory(subDirectory); + if (root == null) + continue; + var names = new ArrayList(); + getOverrides(overrides, tree, root, names); } } - ModpackConfiguration configuration = new ModpackConfiguration<>(manifest, type, name, version, overrides); Files.createDirectories(jsonFile.getParent()); JsonUtils.writeToJsonFile(jsonFile, configuration); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/CompressingUtils.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/CompressingUtils.java index 675f2f9a25..d4875d909c 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/CompressingUtils.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/CompressingUtils.java @@ -133,12 +133,28 @@ public static ZipFileTree openZipTree(Path zipFile) throws IOException { } public static ZipArchiveReader openZipFile(Path zipFile) throws IOException { + return openZipFileWithPossibleEncoding(zipFile, StandardCharsets.UTF_8); + } + + public static ZipArchiveReader openZipFile(Path zipFile, Charset charset) throws IOException { + return new ZipArchiveReader(zipFile, charset); + } + + public static ZipArchiveReader openZipFileWithPossibleEncoding(Path zipFile, Charset possibleEncoding) throws IOException { + if (possibleEncoding == null) + possibleEncoding = StandardCharsets.UTF_8; + ZipArchiveReader zipReader = new ZipArchiveReader(Files.newByteChannel(zipFile)); + Charset suitableEncoding; try { - suitableEncoding = findSuitableEncoding(zipReader); - if (suitableEncoding == StandardCharsets.UTF_8) - return zipReader; + if (possibleEncoding != StandardCharsets.UTF_8 && CompressingUtils.testEncoding(zipReader, possibleEncoding)) { + suitableEncoding = possibleEncoding; + } else { + suitableEncoding = CompressingUtils.findSuitableEncoding(zipReader); + if (suitableEncoding == StandardCharsets.UTF_8) + return zipReader; + } } catch (Throwable e) { IOUtils.closeQuietly(zipReader, e); throw e; @@ -148,10 +164,6 @@ public static ZipArchiveReader openZipFile(Path zipFile) throws IOException { return new ZipArchiveReader(Files.newByteChannel(zipFile), suitableEncoding); } - public static ZipArchiveReader openZipFile(Path zipFile, Charset charset) throws IOException { - return new ZipArchiveReader(zipFile, charset); - } - public static final class Builder { private boolean autoDetectEncoding = false; private Charset encoding = StandardCharsets.UTF_8; diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/Unzipper.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/Unzipper.java index 05542fdbd7..c5cf0c2d78 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/Unzipper.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/Unzipper.java @@ -80,27 +80,6 @@ public Unzipper setTerminateIfSubDirectoryNotExists() { return this; } - private ZipArchiveReader openReader() throws IOException { - ZipArchiveReader zipReader = new ZipArchiveReader(Files.newByteChannel(zipFile)); - - Charset suitableEncoding; - try { - if (encoding != StandardCharsets.UTF_8 && CompressingUtils.testEncoding(zipReader, encoding)) { - suitableEncoding = encoding; - } else { - suitableEncoding = CompressingUtils.findSuitableEncoding(zipReader); - if (suitableEncoding == StandardCharsets.UTF_8) - return zipReader; - } - } catch (Throwable e) { - IOUtils.closeQuietly(zipReader, e); - throw e; - } - - zipReader.close(); - return new ZipArchiveReader(Files.newByteChannel(zipFile), suitableEncoding); - } - /// Decompress the given zip file to a directory. /// /// @throws IOException if zip file is malformed or filesystem error. @@ -113,7 +92,7 @@ public void unzip() throws IOException { : new CopyOption[]{}; long entryCount = 0L; - try (ZipArchiveReader reader = openReader()) { + try (ZipArchiveReader reader = CompressingUtils.openZipFileWithPossibleEncoding(zipFile, encoding)) { String pathPrefix = StringUtils.addSuffix(subDirectory, "/"); for (ZipArchiveEntry entry : reader.getEntries()) { diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/tree/ArchiveFileTree.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/tree/ArchiveFileTree.java index c69adcd983..f96b898c42 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/tree/ArchiveFileTree.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/tree/ArchiveFileTree.java @@ -90,6 +90,22 @@ public Dir getRoot() { } } + public @Nullable Dir getDirectory(@NotNull String dirPath) { + Dir dir = root; + if (dirPath.isEmpty()) { + return dir; + } + String[] path = dirPath.split("/"); + for (String item : path) { + if (item.isEmpty()) + continue; + dir = dir.getSubDirs().get(item); + if (dir == null) + return null; + } + return dir; + } + protected void addEntry(E entry) throws IOException { String[] path = entry.getName().split("/"); List pathList = Arrays.asList(path);