Skip to content

Commit 9706a79

Browse files
committed
feat: custom zipfilesystem.
1 parent ec37b32 commit 9706a79

21 files changed

Lines changed: 1277 additions & 101 deletions

HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLModpackManager.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@
2323
import org.jackhuang.hmcl.task.Task;
2424
import org.jackhuang.hmcl.util.StringUtils;
2525
import org.jackhuang.hmcl.util.gson.JsonUtils;
26-
import org.jackhuang.hmcl.util.io.CompressingUtils;
26+
import org.jackhuang.hmcl.util.io.FileUtils;
2727

2828
import java.io.File;
2929
import java.io.IOException;
3030
import java.nio.charset.Charset;
31-
import java.nio.file.Path;
31+
import java.nio.file.FileSystem;
3232

3333
/**
3434
* @author huangyuhui
@@ -40,20 +40,20 @@ private HMCLModpackManager() {
4040
/**
4141
* Read the manifest in a HMCL modpack.
4242
*
43-
* @param file a HMCL modpack file.
43+
* @param fs a HMCL modpack file.
4444
* @param encoding encoding of modpack zip file.
4545
* @return the manifest of HMCL modpack.
4646
* @throws IOException if the file is not a valid zip file.
4747
* @throws JsonParseException if the manifest.json is missing or malformed.
4848
*/
49-
public static Modpack readHMCLModpackManifest(Path file, Charset encoding) throws IOException, JsonParseException {
50-
String manifestJson = CompressingUtils.readTextZipEntry(file, "modpack.json", encoding);
49+
public static Modpack readHMCLModpackManifest(FileSystem fs, Charset encoding) throws IOException, JsonParseException {
50+
String manifestJson = FileUtils.readText(fs.getPath("modpack.json"));
5151
Modpack manifest = JsonUtils.fromNonNullJson(manifestJson, HMCLModpack.class).setEncoding(encoding);
52-
String gameJson = CompressingUtils.readTextZipEntry(file, "minecraft/pack.json", encoding);
52+
String gameJson = FileUtils.readText(fs.getPath("minecraft/pack.json"));
5353
Version game = JsonUtils.fromNonNullJson(gameJson, Version.class);
5454
if (game.getJar() == null)
5555
if (StringUtils.isBlank(manifest.getVersion()))
56-
throw new JsonParseException("Cannot recognize the game version of modpack " + file + ".");
56+
throw new JsonParseException("Cannot recognize the game version of modpack");
5757
else
5858
manifest.setManifest(HMCLModpackManifest.INSTANCE);
5959
else

HMCL/src/main/java/org/jackhuang/hmcl/game/ModpackHelper.java

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import org.jackhuang.hmcl.util.gson.JsonUtils;
4242
import org.jackhuang.hmcl.util.io.CompressingUtils;
4343
import org.jackhuang.hmcl.util.io.FileUtils;
44+
import org.jackhuang.hmcl.util.io.ZipFileSystem;
4445

4546
import java.io.File;
4647
import java.io.FileNotFoundException;
@@ -61,34 +62,38 @@ public final class ModpackHelper {
6162
private ModpackHelper() {}
6263

6364
public static Modpack readModpackManifest(Path file, Charset charset) throws UnsupportedModpackException, ManuallyCreatedModpackException {
64-
try {
65-
return McbbsModpackManifest.readManifest(file, charset);
66-
} catch (Exception ignored) {
67-
// ignore it, not a valid MCBBS modpack.
68-
}
65+
try (ZipFileSystem zfs = CompressingUtils.createReadOnlyZipFileSystem(file, charset)) {
66+
try {
67+
return McbbsModpackManifest.readManifest(zfs, charset);
68+
} catch (Exception ignored) {
69+
// ignore it, not a valid MCBBS modpack.
70+
}
6971

70-
try {
71-
return CurseManifest.readCurseForgeModpackManifest(file, charset);
72-
} catch (Exception e) {
73-
// ignore it, not a valid CurseForge modpack.
74-
}
72+
try {
73+
return CurseManifest.readCurseForgeModpackManifest(zfs, charset);
74+
} catch (Exception e) {
75+
// ignore it, not a valid CurseForge modpack.
76+
}
7577

76-
try {
77-
return HMCLModpackManager.readHMCLModpackManifest(file, charset);
78-
} catch (Exception e) {
79-
// ignore it, not a valid HMCL modpack.
80-
}
78+
try {
79+
return HMCLModpackManager.readHMCLModpackManifest(zfs, charset);
80+
} catch (Exception e) {
81+
// ignore it, not a valid HMCL modpack.
82+
}
8183

82-
try {
83-
return MultiMCInstanceConfiguration.readMultiMCModpackManifest(file, charset);
84-
} catch (Exception e) {
85-
// ignore it, not a valid MultiMC modpack.
86-
}
84+
try {
85+
return MultiMCInstanceConfiguration.readMultiMCModpackManifest(zfs, file, charset);
86+
} catch (Exception e) {
87+
// ignore it, not a valid MultiMC modpack.
88+
}
8789

88-
try {
89-
return ServerModpackManifest.readManifest(file, charset);
90-
} catch (Exception e) {
91-
// ignore it, not a valid Server modpack.
90+
try {
91+
return ServerModpackManifest.readManifest(zfs, charset);
92+
} catch (Exception e) {
93+
// ignore it, not a valid Server modpack.
94+
}
95+
96+
} catch (IOException ignored) {
9297
}
9398

9499
try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(file, charset)) {

HMCL/src/main/java/org/jackhuang/hmcl/upgrade/HMCLDownloadTask.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import org.jackhuang.hmcl.task.FileDownloadTask;
2121
import org.jackhuang.hmcl.util.Pack200Utils;
22+
import org.jackhuang.hmcl.util.io.FileUtils;
2223
import org.jackhuang.hmcl.util.io.NetworkUtils;
2324
import org.tukaani.xz.XZInputStream;
2425

@@ -49,7 +50,7 @@ public void execute() throws Exception {
4950
break;
5051

5152
case PACK_XZ:
52-
byte[] raw = Files.readAllBytes(target);
53+
byte[] raw = FileUtils.readAllBytes(target);
5354
try (InputStream in = new XZInputStream(new ByteArrayInputStream(raw));
5455
JarOutputStream out = new JarOutputStream(Files.newOutputStream(target))) {
5556
Pack200Utils.unpack(in, out);

HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/LibraryDownloadTask.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ else if (t instanceof CancellationException)
103103
else
104104
throw new LibraryDownloadException(library, t);
105105
} else {
106-
if (xz) unpackLibrary(jar, Files.readAllBytes(xzFile.toPath()));
106+
if (xz) unpackLibrary(jar, FileUtils.readAllBytes(xzFile.toPath()));
107107
}
108108
}
109109

@@ -180,7 +180,7 @@ public static boolean checksumValid(File libPath, List<String> checksums) {
180180
if (checksums == null || checksums.isEmpty()) {
181181
return true;
182182
}
183-
byte[] fileData = Files.readAllBytes(libPath.toPath());
183+
byte[] fileData = FileUtils.readAllBytes(libPath.toPath());
184184
boolean valid = checksums.contains(encodeHex(digest("SHA-1", fileData)));
185185
if (!valid && libPath.getName().endsWith(".jar")) {
186186
valid = validateJar(fileData, checksums);

HMCLCore/src/main/java/org/jackhuang/hmcl/download/optifine/OptiFineInstallTask.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ public static Task<Version> install(DefaultDependencyManager dependencyManager,
230230
Path configClass = fs.getPath("Config.class");
231231
if (!Files.exists(configClass)) configClass = fs.getPath("net/optifine/Config.class");
232232
if (!Files.exists(configClass)) throw new IOException("Unrecognized installer");
233-
ConstantPool pool = ConstantPoolScanner.parse(Files.readAllBytes(configClass), ConstantType.UTF8);
233+
ConstantPool pool = ConstantPoolScanner.parse(FileUtils.readAllBytes(configClass), ConstantType.UTF8);
234234
List<String> constants = new ArrayList<>();
235235
pool.list(Utf8Constant.class).forEach(utf8 -> constants.add(utf8.get()));
236236
String mcVersion = getOrDefault(constants, constants.indexOf("MC_VERSION") + 1, null);

HMCLCore/src/main/java/org/jackhuang/hmcl/game/GameVersion.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,13 +104,13 @@ public static Optional<String> minecraftVersion(File file) {
104104

105105
Path minecraft = gameJar.getPath("net/minecraft/client/Minecraft.class");
106106
if (Files.exists(minecraft)) {
107-
Optional<String> result = getVersionOfClassMinecraft(Files.readAllBytes(minecraft));
107+
Optional<String> result = getVersionOfClassMinecraft(FileUtils.readAllBytes(minecraft));
108108
if (result.isPresent())
109109
return result;
110110
}
111111
Path minecraftServer = gameJar.getPath("net/minecraft/server/MinecraftServer.class");
112112
if (Files.exists(minecraftServer))
113-
return getVersionFromClassMinecraftServer(Files.readAllBytes(minecraftServer));
113+
return getVersionFromClassMinecraftServer(FileUtils.readAllBytes(minecraftServer));
114114
return Optional.empty();
115115
} catch (IOException e) {
116116
return Optional.empty();

HMCLCore/src/main/java/org/jackhuang/hmcl/mod/curse/CurseManifest.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,14 @@
2323
import org.jackhuang.hmcl.mod.Modpack;
2424
import org.jackhuang.hmcl.task.Task;
2525
import org.jackhuang.hmcl.util.Immutable;
26+
import org.jackhuang.hmcl.util.Lang;
2627
import org.jackhuang.hmcl.util.gson.JsonUtils;
27-
import org.jackhuang.hmcl.util.io.CompressingUtils;
28+
import org.jackhuang.hmcl.util.io.FileUtils;
29+
import org.jackhuang.hmcl.util.io.ZipFileSystem;
2830

2931
import java.io.File;
3032
import java.io.IOException;
3133
import java.nio.charset.Charset;
32-
import java.nio.file.Path;
3334
import java.util.Collections;
3435
import java.util.List;
3536

@@ -121,11 +122,11 @@ public CurseManifest setFiles(List<CurseManifestFile> files) {
121122
* @throws JsonParseException if the manifest.json is missing or malformed.
122123
* @return the manifest.
123124
*/
124-
public static Modpack readCurseForgeModpackManifest(Path zip, Charset encoding) throws IOException, JsonParseException {
125-
String json = CompressingUtils.readTextZipEntry(zip, "manifest.json", encoding);
125+
public static Modpack readCurseForgeModpackManifest(ZipFileSystem zip, Charset encoding) throws IOException, JsonParseException {
126+
String json = FileUtils.readText(zip.getPath("manifest.json"));
126127
CurseManifest manifest = JsonUtils.fromNonNullJson(json, CurseManifest.class);
127128
return new Modpack(manifest.getName(), manifest.getAuthor(), manifest.getVersion(), manifest.getMinecraft().getGameVersion(),
128-
CompressingUtils.readTextZipEntryQuietly(zip, "modlist.html", encoding).orElse( "No description"), encoding, manifest) {
129+
Lang.ignoringException(() -> FileUtils.readText(zip.getPath("modlist.html")), "No description"), encoding, manifest) {
129130
@Override
130131
public Task<?> getInstallTask(DefaultDependencyManager dependencyManager, File zipFile, String name) {
131132
return new CurseInstallTask(dependencyManager, zipFile, this, manifest, name);

HMCLCore/src/main/java/org/jackhuang/hmcl/mod/mcbbs/McbbsModpackManifest.java

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,13 @@
2525
import org.jackhuang.hmcl.mod.Modpack;
2626
import org.jackhuang.hmcl.task.Task;
2727
import org.jackhuang.hmcl.util.gson.*;
28-
import org.jackhuang.hmcl.util.io.CompressingUtils;
2928
import org.jackhuang.hmcl.util.io.FileUtils;
3029
import org.jackhuang.hmcl.util.io.NetworkUtils;
3130
import org.jetbrains.annotations.Nullable;
3231

3332
import java.io.IOException;
3433
import java.net.URL;
3534
import java.nio.charset.Charset;
36-
import java.nio.charset.StandardCharsets;
3735
import java.nio.file.FileSystem;
3836
import java.nio.file.Files;
3937
import java.nio.file.Path;
@@ -435,29 +433,26 @@ public void injectLaunchOptions(LaunchOptions.Builder launchOptions) {
435433
}
436434

437435
private static Modpack fromManifestFile(Path manifestFile, Charset encoding) throws IOException, JsonParseException {
438-
String json = FileUtils.readText(manifestFile, StandardCharsets.UTF_8);
439-
McbbsModpackManifest manifest = JsonUtils.fromNonNullJson(json, McbbsModpackManifest.class);
436+
McbbsModpackManifest manifest = JsonUtils.fromNonNullJson(FileUtils.readText(manifestFile), McbbsModpackManifest.class);
440437
return manifest.toModpack(encoding);
441438
}
442439

443440
/**
444-
* @param zip the MCBBS modpack file.
441+
* @param fs the MCBBS modpack file.
445442
* @param encoding the modpack zip file encoding.
446-
* @throws IOException if the file is not a valid zip file.
447-
* @throws JsonParseException if the server-manifest.json is missing or malformed.
448443
* @return the manifest.
444+
* @throws IOException if the file is not a valid zip file.
445+
* @throws JsonParseException if the server-manifest.json is missing or malformed.
449446
*/
450-
public static Modpack readManifest(Path zip, Charset encoding) throws IOException, JsonParseException {
451-
try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(zip, encoding)) {
452-
Path mcbbsPackMeta = fs.getPath("mcbbs.packmeta");
453-
if (Files.exists(mcbbsPackMeta)) {
454-
return fromManifestFile(mcbbsPackMeta, encoding);
455-
}
456-
Path manifestJson = fs.getPath("manifest.json");
457-
if (Files.exists(manifestJson)) {
458-
return fromManifestFile(manifestJson, encoding);
459-
}
460-
throw new IOException("`mcbbs.packmeta` or `manifest.json` cannot be found");
447+
public static Modpack readManifest(FileSystem fs, Charset encoding) throws IOException, JsonParseException {
448+
Path mcbbsPackMeta = fs.getPath("mcbbs.packmeta");
449+
if (Files.exists(mcbbsPackMeta)) {
450+
return fromManifestFile(mcbbsPackMeta, encoding);
451+
}
452+
Path manifestJson = fs.getPath("manifest.json");
453+
if (Files.exists(manifestJson)) {
454+
return fromManifestFile(manifestJson, encoding);
461455
}
456+
throw new IOException("`mcbbs.packmeta` or `manifest.json` cannot be found");
462457
}
463458
}

HMCLCore/src/main/java/org/jackhuang/hmcl/mod/multimc/MultiMCInstanceConfiguration.java

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* Hello Minecraft! Launcher
3-
* Copyright (C) 2020 huangyuhui <huanghongxun2008@126.com> and contributors
3+
* Copyright (C) 2021 huangyuhui <huanghongxun2008@126.com> and contributors
44
*
55
* This program is free software: you can redistribute it and/or modify
66
* it under the terms of the GNU General Public License as published by
@@ -21,16 +21,15 @@
2121
import org.jackhuang.hmcl.mod.Modpack;
2222
import org.jackhuang.hmcl.task.Task;
2323
import org.jackhuang.hmcl.util.Lang;
24-
import org.jackhuang.hmcl.util.io.CompressingUtils;
2524
import org.jackhuang.hmcl.util.io.FileUtils;
25+
import org.jackhuang.hmcl.util.io.ZipFileSystem;
2626

2727
import java.io.File;
2828
import java.io.IOException;
2929
import java.io.InputStream;
3030
import java.io.InputStreamReader;
3131
import java.nio.charset.Charset;
3232
import java.nio.charset.StandardCharsets;
33-
import java.nio.file.FileSystem;
3433
import java.nio.file.Files;
3534
import java.nio.file.Path;
3635
import java.util.Optional;
@@ -348,24 +347,22 @@ public static Path getRootPath(Path root) throws IOException {
348347
}
349348
}
350349

351-
public static Modpack readMultiMCModpackManifest(Path modpackFile, Charset encoding) throws IOException {
352-
try (FileSystem fs = CompressingUtils.readonly(modpackFile).setEncoding(encoding).build()) {
353-
Path root = getRootPath(fs.getPath("/"));
354-
MultiMCManifest manifest = MultiMCManifest.readMultiMCModpackManifest(root);
355-
String name = FileUtils.getName(root, FileUtils.getNameWithoutExtension(modpackFile));
356-
357-
Path instancePath = root.resolve("instance.cfg");
358-
if (Files.notExists(instancePath))
359-
throw new IOException("`instance.cfg` not found, " + modpackFile + " is not a valid MultiMC modpack.");
360-
try (InputStream instanceStream = Files.newInputStream(instancePath)) {
361-
MultiMCInstanceConfiguration cfg = new MultiMCInstanceConfiguration(name, instanceStream, manifest);
362-
return new Modpack(cfg.getName(), "", "", cfg.getGameVersion(), cfg.getNotes(), encoding, cfg) {
363-
@Override
364-
public Task<?> getInstallTask(DefaultDependencyManager dependencyManager, File zipFile, String name) {
365-
return new MultiMCModpackInstallTask(dependencyManager, zipFile, this, cfg, name);
366-
}
367-
};
368-
}
350+
public static Modpack readMultiMCModpackManifest(ZipFileSystem zipFile, Path filePath, Charset encoding) throws IOException {
351+
Path root = getRootPath(zipFile.getPath("/"));
352+
MultiMCManifest manifest = MultiMCManifest.readMultiMCModpackManifest(root);
353+
String name = FileUtils.getNameWithoutExtension(filePath);
354+
355+
Path instancePath = root.resolve("instance.cfg");
356+
if (Files.notExists(instancePath))
357+
throw new IOException("`instance.cfg` not found, " + filePath + " is not a valid MultiMC modpack.");
358+
try (InputStream instanceStream = Files.newInputStream(instancePath)) {
359+
MultiMCInstanceConfiguration cfg = new MultiMCInstanceConfiguration(name, instanceStream, manifest);
360+
return new Modpack(cfg.getName(), "", "", cfg.getGameVersion(), cfg.getNotes(), encoding, cfg) {
361+
@Override
362+
public Task<?> getInstallTask(DefaultDependencyManager dependencyManager, File zipFile, String name) {
363+
return new MultiMCModpackInstallTask(dependencyManager, zipFile, this, cfg, name);
364+
}
365+
};
369366
}
370367
}
371368
}

HMCLCore/src/main/java/org/jackhuang/hmcl/mod/multimc/MultiMCModpackInstallTask.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.jackhuang.hmcl.util.gson.JsonUtils;
3333
import org.jackhuang.hmcl.util.io.CompressingUtils;
3434
import org.jackhuang.hmcl.util.io.FileUtils;
35+
import org.jackhuang.hmcl.util.io.ZipFileSystem;
3536

3637
import java.io.File;
3738
import java.io.IOException;
@@ -144,11 +145,11 @@ public List<Task<?>> getDependents() {
144145
public void execute() throws Exception {
145146
Version version = repository.readVersionJson(name);
146147

147-
try (FileSystem fs = CompressingUtils.readonly(zipFile.toPath()).setAutoDetectEncoding(true).build()) {
148+
try (ZipFileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(zipFile.toPath())) {
148149
Path root = MultiMCInstanceConfiguration.getRootPath(fs.getPath("/"));
149150
Path patches = root.resolve("patches");
150151

151-
if (Files.exists(patches)) {
152+
if (Files.isDirectory(patches)) {
152153
try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(patches)) {
153154
for (Path patchJson : directoryStream) {
154155
if (patchJson.toString().endsWith(".json")) {

0 commit comments

Comments
 (0)