@@ -17,19 +17,22 @@
|
|||||||
*/
|
*/
|
||||||
package org.jackhuang.hmcl.mod;
|
package org.jackhuang.hmcl.mod;
|
||||||
|
|
||||||
|
import kala.compress.archivers.zip.ZipArchiveEntry;
|
||||||
import org.jackhuang.hmcl.task.Task;
|
import org.jackhuang.hmcl.task.Task;
|
||||||
import org.jackhuang.hmcl.util.DigestUtils;
|
import org.jackhuang.hmcl.util.DigestUtils;
|
||||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||||
import org.jackhuang.hmcl.util.io.CompressingUtils;
|
import org.jackhuang.hmcl.util.io.CompressingUtils;
|
||||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
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.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.nio.file.*;
|
import java.nio.file.*;
|
||||||
import java.nio.file.attribute.BasicFileAttributes;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public final class MinecraftInstanceTask<T> extends Task<ModpackConfiguration<T>> {
|
public final class MinecraftInstanceTask<T> extends Task<ModpackConfiguration<T>> {
|
||||||
|
|
||||||
@@ -53,26 +56,42 @@ public final class MinecraftInstanceTask<T> extends Task<ModpackConfiguration<T>
|
|||||||
this.version = version;
|
this.version = version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void getOverrides(List<ModpackConfiguration.FileInformation> overrides,
|
||||||
|
ZipFileTree tree,
|
||||||
|
ArchiveFileTree.Dir<ZipArchiveEntry> dir,
|
||||||
|
List<String> names) throws IOException {
|
||||||
|
String prefix = String.join("/", names);
|
||||||
|
if (!prefix.isEmpty())
|
||||||
|
prefix = prefix + "/";
|
||||||
|
|
||||||
|
for (Map.Entry<String, ZipArchiveEntry> 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<ZipArchiveEntry> subDir : dir.getSubDirs().values()) {
|
||||||
|
names.add(subDir.getName());
|
||||||
|
getOverrides(overrides, tree, subDir, names);
|
||||||
|
names.remove(names.size() - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute() throws Exception {
|
public void execute() throws Exception {
|
||||||
List<ModpackConfiguration.FileInformation> overrides = new ArrayList<>();
|
List<ModpackConfiguration.FileInformation> 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) {
|
for (String subDirectory : subDirectories) {
|
||||||
Path root = fs.getPath(subDirectory);
|
ArchiveFileTree.Dir<ZipArchiveEntry> root = tree.getDirectory(subDirectory);
|
||||||
|
if (root == null)
|
||||||
if (Files.exists(root))
|
continue;
|
||||||
Files.walkFileTree(root, new SimpleFileVisitor<>() {
|
var names = new ArrayList<String>();
|
||||||
@Override
|
getOverrides(overrides, tree, root, names);
|
||||||
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;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ModpackConfiguration<T> configuration = new ModpackConfiguration<>(manifest, type, name, version, overrides);
|
ModpackConfiguration<T> configuration = new ModpackConfiguration<>(manifest, type, name, version, overrides);
|
||||||
Files.createDirectories(jsonFile.getParent());
|
Files.createDirectories(jsonFile.getParent());
|
||||||
JsonUtils.writeToJsonFile(jsonFile, configuration);
|
JsonUtils.writeToJsonFile(jsonFile, configuration);
|
||||||
|
|||||||
@@ -133,12 +133,28 @@ public final class CompressingUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static ZipArchiveReader openZipFile(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));
|
ZipArchiveReader zipReader = new ZipArchiveReader(Files.newByteChannel(zipFile));
|
||||||
|
|
||||||
Charset suitableEncoding;
|
Charset suitableEncoding;
|
||||||
try {
|
try {
|
||||||
suitableEncoding = findSuitableEncoding(zipReader);
|
if (possibleEncoding != StandardCharsets.UTF_8 && CompressingUtils.testEncoding(zipReader, possibleEncoding)) {
|
||||||
|
suitableEncoding = possibleEncoding;
|
||||||
|
} else {
|
||||||
|
suitableEncoding = CompressingUtils.findSuitableEncoding(zipReader);
|
||||||
if (suitableEncoding == StandardCharsets.UTF_8)
|
if (suitableEncoding == StandardCharsets.UTF_8)
|
||||||
return zipReader;
|
return zipReader;
|
||||||
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
IOUtils.closeQuietly(zipReader, e);
|
IOUtils.closeQuietly(zipReader, e);
|
||||||
throw e;
|
throw e;
|
||||||
@@ -148,10 +164,6 @@ public final class CompressingUtils {
|
|||||||
return new ZipArchiveReader(Files.newByteChannel(zipFile), suitableEncoding);
|
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 {
|
public static final class Builder {
|
||||||
private boolean autoDetectEncoding = false;
|
private boolean autoDetectEncoding = false;
|
||||||
private Charset encoding = StandardCharsets.UTF_8;
|
private Charset encoding = StandardCharsets.UTF_8;
|
||||||
|
|||||||
@@ -80,27 +80,6 @@ public final class Unzipper {
|
|||||||
return this;
|
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.
|
/// Decompress the given zip file to a directory.
|
||||||
///
|
///
|
||||||
/// @throws IOException if zip file is malformed or filesystem error.
|
/// @throws IOException if zip file is malformed or filesystem error.
|
||||||
@@ -113,7 +92,7 @@ public final class Unzipper {
|
|||||||
: new CopyOption[]{};
|
: new CopyOption[]{};
|
||||||
|
|
||||||
long entryCount = 0L;
|
long entryCount = 0L;
|
||||||
try (ZipArchiveReader reader = openReader()) {
|
try (ZipArchiveReader reader = CompressingUtils.openZipFileWithPossibleEncoding(zipFile, encoding)) {
|
||||||
String pathPrefix = StringUtils.addSuffix(subDirectory, "/");
|
String pathPrefix = StringUtils.addSuffix(subDirectory, "/");
|
||||||
|
|
||||||
for (ZipArchiveEntry entry : reader.getEntries()) {
|
for (ZipArchiveEntry entry : reader.getEntries()) {
|
||||||
|
|||||||
@@ -90,6 +90,22 @@ public abstract class ArchiveFileTree<R, E extends ArchiveEntry> implements Clos
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public @Nullable Dir<E> getDirectory(@NotNull String dirPath) {
|
||||||
|
Dir<E> 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 {
|
protected void addEntry(E entry) throws IOException {
|
||||||
String[] path = entry.getName().split("/");
|
String[] path = entry.getName().split("/");
|
||||||
List<String> pathList = Arrays.asList(path);
|
List<String> pathList = Arrays.asList(path);
|
||||||
|
|||||||
Reference in New Issue
Block a user