使用 kala-compress 读取模组元数据 (#5146)
This commit is contained in:
@@ -25,6 +25,7 @@ import org.jackhuang.hmcl.util.Pair;
|
|||||||
import org.jackhuang.hmcl.util.StringUtils;
|
import org.jackhuang.hmcl.util.StringUtils;
|
||||||
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.ZipFileTree;
|
||||||
import org.jackhuang.hmcl.util.versioning.VersionNumber;
|
import org.jackhuang.hmcl.util.versioning.VersionNumber;
|
||||||
import org.jetbrains.annotations.Unmodifiable;
|
import org.jetbrains.annotations.Unmodifiable;
|
||||||
|
|
||||||
@@ -38,7 +39,7 @@ import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
|||||||
public final class ModManager {
|
public final class ModManager {
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
private interface ModMetadataReader {
|
private interface ModMetadataReader {
|
||||||
LocalModFile fromFile(ModManager modManager, Path modFile, FileSystem fs) throws IOException, JsonParseException;
|
LocalModFile fromFile(ModManager modManager, Path modFile, ZipFileTree tree) throws IOException, JsonParseException;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Map<String, List<Pair<ModMetadataReader, ModLoaderType>>> READERS;
|
private static final Map<String, List<Pair<ModMetadataReader, ModLoaderType>>> READERS;
|
||||||
@@ -125,10 +126,10 @@ public final class ModManager {
|
|||||||
LocalModFile modInfo = null;
|
LocalModFile modInfo = null;
|
||||||
|
|
||||||
List<Exception> exceptions = new ArrayList<>();
|
List<Exception> exceptions = new ArrayList<>();
|
||||||
try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(file)) {
|
try (ZipFileTree tree = CompressingUtils.openZipTree(file)) {
|
||||||
for (ModMetadataReader reader : supportedReaders) {
|
for (ModMetadataReader reader : supportedReaders) {
|
||||||
try {
|
try {
|
||||||
modInfo = reader.fromFile(this, file, fs);
|
modInfo = reader.fromFile(this, file, tree);
|
||||||
break;
|
break;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
exceptions.add(e);
|
exceptions.add(e);
|
||||||
@@ -138,7 +139,7 @@ public final class ModManager {
|
|||||||
if (modInfo == null) {
|
if (modInfo == null) {
|
||||||
for (ModMetadataReader reader : unsupportedReaders) {
|
for (ModMetadataReader reader : unsupportedReaders) {
|
||||||
try {
|
try {
|
||||||
modInfo = reader.fromFile(this, file, fs);
|
modInfo = reader.fromFile(this, file, tree);
|
||||||
break;
|
break;
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,16 +19,16 @@ package org.jackhuang.hmcl.mod.modinfo;
|
|||||||
|
|
||||||
import com.google.gson.*;
|
import com.google.gson.*;
|
||||||
import com.google.gson.annotations.JsonAdapter;
|
import com.google.gson.annotations.JsonAdapter;
|
||||||
|
import kala.compress.archivers.zip.ZipArchiveEntry;
|
||||||
import org.jackhuang.hmcl.mod.LocalModFile;
|
import org.jackhuang.hmcl.mod.LocalModFile;
|
||||||
import org.jackhuang.hmcl.mod.ModLoaderType;
|
import org.jackhuang.hmcl.mod.ModLoaderType;
|
||||||
import org.jackhuang.hmcl.mod.ModManager;
|
import org.jackhuang.hmcl.mod.ModManager;
|
||||||
import org.jackhuang.hmcl.util.Immutable;
|
import org.jackhuang.hmcl.util.Immutable;
|
||||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||||
|
import org.jackhuang.hmcl.util.tree.ZipFileTree;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.nio.file.FileSystem;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -59,11 +59,11 @@ public final class FabricModMetadata {
|
|||||||
this.contact = contact;
|
this.contact = contact;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LocalModFile fromFile(ModManager modManager, Path modFile, FileSystem fs) throws IOException, JsonParseException {
|
public static LocalModFile fromFile(ModManager modManager, Path modFile, ZipFileTree tree) throws IOException, JsonParseException {
|
||||||
Path mcmod = fs.getPath("fabric.mod.json");
|
ZipArchiveEntry mcmod = tree.getEntry("fabric.mod.json");
|
||||||
if (Files.notExists(mcmod))
|
if (mcmod == null)
|
||||||
throw new IOException("File " + modFile + " is not a Fabric mod.");
|
throw new IOException("File " + modFile + " is not a Fabric mod.");
|
||||||
FabricModMetadata metadata = JsonUtils.fromNonNullJson(Files.readString(mcmod), FabricModMetadata.class);
|
FabricModMetadata metadata = JsonUtils.fromNonNullJsonFully(tree.getInputStream(mcmod), FabricModMetadata.class);
|
||||||
String authors = metadata.authors == null ? "" : metadata.authors.stream().map(author -> author.name).collect(Collectors.joining(", "));
|
String authors = metadata.authors == null ? "" : metadata.authors.stream().map(author -> author.name).collect(Collectors.joining(", "));
|
||||||
return new LocalModFile(modManager, modManager.getLocalMod(metadata.id, ModLoaderType.FABRIC), modFile, metadata.name, new LocalModFile.Description(metadata.description),
|
return new LocalModFile(modManager, modManager.getLocalMod(metadata.id, ModLoaderType.FABRIC), modFile, metadata.name, new LocalModFile.Description(metadata.description),
|
||||||
authors, metadata.version, "", metadata.contact != null ? metadata.contact.getOrDefault("homepage", "") : "", metadata.icon);
|
authors, metadata.version, "", metadata.contact != null ? metadata.contact.getOrDefault("homepage", "") : "", metadata.icon);
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import com.google.gson.JsonParseException;
|
|||||||
import com.google.gson.JsonPrimitive;
|
import com.google.gson.JsonPrimitive;
|
||||||
import com.google.gson.annotations.JsonAdapter;
|
import com.google.gson.annotations.JsonAdapter;
|
||||||
import com.moandjiezana.toml.Toml;
|
import com.moandjiezana.toml.Toml;
|
||||||
|
import kala.compress.archivers.zip.ZipArchiveEntry;
|
||||||
import org.jackhuang.hmcl.mod.LocalModFile;
|
import org.jackhuang.hmcl.mod.LocalModFile;
|
||||||
import org.jackhuang.hmcl.mod.ModLoaderType;
|
import org.jackhuang.hmcl.mod.ModLoaderType;
|
||||||
import org.jackhuang.hmcl.mod.ModManager;
|
import org.jackhuang.hmcl.mod.ModManager;
|
||||||
@@ -16,14 +17,13 @@ import org.jackhuang.hmcl.util.gson.JsonSerializable;
|
|||||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||||
import org.jackhuang.hmcl.util.gson.Validation;
|
import org.jackhuang.hmcl.util.gson.Validation;
|
||||||
import org.jackhuang.hmcl.util.io.CompressingUtils;
|
import org.jackhuang.hmcl.util.io.CompressingUtils;
|
||||||
|
import org.jackhuang.hmcl.util.tree.ZipFileTree;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.nio.file.FileSystem;
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.StandardCopyOption;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -149,33 +149,33 @@ public final class ForgeNewModMetadata {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LocalModFile fromForgeFile(ModManager modManager, Path modFile, FileSystem fs) throws IOException {
|
public static LocalModFile fromForgeFile(ModManager modManager, Path modFile, ZipFileTree tree) throws IOException {
|
||||||
return fromFile(modManager, modFile, fs, ModLoaderType.FORGE);
|
return fromFile(modManager, modFile, tree, ModLoaderType.FORGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LocalModFile fromNeoForgeFile(ModManager modManager, Path modFile, FileSystem fs) throws IOException {
|
public static LocalModFile fromNeoForgeFile(ModManager modManager, Path modFile, ZipFileTree tree) throws IOException {
|
||||||
return fromFile(modManager, modFile, fs, ModLoaderType.NEO_FORGED);
|
return fromFile(modManager, modFile, tree, ModLoaderType.NEO_FORGED);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static LocalModFile fromFile(ModManager modManager, Path modFile, FileSystem fs, ModLoaderType modLoaderType) throws IOException {
|
private static LocalModFile fromFile(ModManager modManager, Path modFile, ZipFileTree tree, ModLoaderType modLoaderType) throws IOException {
|
||||||
if (modLoaderType != ModLoaderType.FORGE && modLoaderType != ModLoaderType.NEO_FORGED) {
|
if (modLoaderType != ModLoaderType.FORGE && modLoaderType != ModLoaderType.NEO_FORGED) {
|
||||||
throw new IOException("Invalid mod loader: " + modLoaderType);
|
throw new IOException("Invalid mod loader: " + modLoaderType);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (modLoaderType == ModLoaderType.NEO_FORGED) {
|
if (modLoaderType == ModLoaderType.NEO_FORGED) {
|
||||||
try {
|
try {
|
||||||
return fromFile0("META-INF/neoforge.mods.toml", modLoaderType, modManager, modFile, fs);
|
return fromFile0("META-INF/neoforge.mods.toml", modLoaderType, modManager, modFile, tree);
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return fromFile0("META-INF/mods.toml", modLoaderType, modManager, modFile, fs);
|
return fromFile0("META-INF/mods.toml", modLoaderType, modManager, modFile, tree);
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return fromEmbeddedMod(modManager, modFile, fs, modLoaderType);
|
return fromEmbeddedMod(modManager, modFile, tree, modLoaderType);
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,19 +187,19 @@ public final class ForgeNewModMetadata {
|
|||||||
ModLoaderType modLoaderType,
|
ModLoaderType modLoaderType,
|
||||||
ModManager modManager,
|
ModManager modManager,
|
||||||
Path modFile,
|
Path modFile,
|
||||||
FileSystem fs) throws IOException, JsonParseException {
|
ZipFileTree tree) throws IOException, JsonParseException {
|
||||||
Path modToml = fs.getPath(tomlPath);
|
ZipArchiveEntry modToml = tree.getEntry(tomlPath);
|
||||||
if (Files.notExists(modToml))
|
if (modToml == null)
|
||||||
throw new IOException("File " + modFile + " is not a Forge 1.13+ or NeoForge mod.");
|
throw new IOException("File " + modFile + " is not a Forge 1.13+ or NeoForge mod.");
|
||||||
Toml toml = new Toml().read(Files.readString(modToml));
|
Toml toml = new Toml().read(tree.readTextEntry(modToml));
|
||||||
ForgeNewModMetadata metadata = toml.to(ForgeNewModMetadata.class);
|
ForgeNewModMetadata metadata = toml.to(ForgeNewModMetadata.class);
|
||||||
if (metadata == null || metadata.getMods().isEmpty())
|
if (metadata == null || metadata.getMods().isEmpty())
|
||||||
throw new IOException("Mod " + modFile + " `mods.toml` is malformed..");
|
throw new IOException("Mod " + modFile + " `mods.toml` is malformed..");
|
||||||
Mod mod = metadata.getMods().get(0);
|
Mod mod = metadata.getMods().get(0);
|
||||||
Path manifestMF = fs.getPath("META-INF/MANIFEST.MF");
|
ZipArchiveEntry manifestMF = tree.getEntry("META-INF/MANIFEST.MF");
|
||||||
String jarVersion = "";
|
String jarVersion = "";
|
||||||
if (Files.exists(manifestMF)) {
|
if (manifestMF != null) {
|
||||||
try (InputStream is = Files.newInputStream(manifestMF)) {
|
try (InputStream is = tree.getInputStream(manifestMF)) {
|
||||||
Manifest manifest = new Manifest(is);
|
Manifest manifest = new Manifest(is);
|
||||||
jarVersion = manifest.getMainAttributes().getValue(Attributes.Name.IMPLEMENTATION_VERSION);
|
jarVersion = manifest.getMainAttributes().getValue(Attributes.Name.IMPLEMENTATION_VERSION);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -215,30 +215,30 @@ public final class ForgeNewModMetadata {
|
|||||||
metadata.getLogoFile());
|
metadata.getLogoFile());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static LocalModFile fromEmbeddedMod(ModManager modManager, Path modFile, FileSystem fs, ModLoaderType modLoaderType) throws IOException {
|
private static LocalModFile fromEmbeddedMod(ModManager modManager, Path modFile, ZipFileTree tree, ModLoaderType modLoaderType) throws IOException {
|
||||||
Path manifestFile = fs.getPath("META-INF/MANIFEST.MF");
|
ZipArchiveEntry manifestFile = tree.getEntry("META-INF/MANIFEST.MF");
|
||||||
if (!Files.isRegularFile(manifestFile))
|
if (manifestFile == null)
|
||||||
throw new IOException("Missing MANIFEST.MF in file " + manifestFile);
|
throw new IOException("Missing MANIFEST.MF in file " + modFile);
|
||||||
|
|
||||||
Manifest manifest;
|
Manifest manifest;
|
||||||
try (InputStream input = Files.newInputStream(manifestFile)) {
|
try (InputStream input = tree.getInputStream(manifestFile)) {
|
||||||
manifest = new Manifest(input);
|
manifest = new Manifest(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Path> embeddedModFiles = List.of();
|
List<ZipArchiveEntry> embeddedModFiles = List.of();
|
||||||
|
|
||||||
String embeddedDependenciesMod = manifest.getMainAttributes().getValue("Embedded-Dependencies-Mod");
|
String embeddedDependenciesMod = manifest.getMainAttributes().getValue("Embedded-Dependencies-Mod");
|
||||||
if (embeddedDependenciesMod != null) {
|
if (embeddedDependenciesMod != null) {
|
||||||
Path embeddedModFile = fs.getPath(embeddedDependenciesMod);
|
ZipArchiveEntry embeddedModFile = tree.getEntry(embeddedDependenciesMod);
|
||||||
if (!Files.isRegularFile(embeddedModFile)) {
|
if (embeddedModFile == null) {
|
||||||
LOG.warning("Missing embedded-dependencies-mod: " + embeddedModFile);
|
LOG.warning("Missing embedded-dependencies-mod: " + embeddedDependenciesMod);
|
||||||
throw new IOException();
|
throw new IOException();
|
||||||
}
|
}
|
||||||
embeddedModFiles = List.of(embeddedModFile);
|
embeddedModFiles = List.of(embeddedModFile);
|
||||||
} else {
|
} else {
|
||||||
Path jarInJarMetadata = fs.getPath("META-INF/jarjar/metadata.json");
|
ZipArchiveEntry jarInJarMetadata = tree.getEntry("META-INF/jarjar/metadata.json");
|
||||||
if (Files.isRegularFile(jarInJarMetadata)) {
|
if (jarInJarMetadata != null) {
|
||||||
JarInJarMetadata metadata = JsonUtils.fromJsonFile(jarInJarMetadata, JarInJarMetadata.class);
|
JarInJarMetadata metadata = JsonUtils.fromJsonFully(tree.getInputStream(jarInJarMetadata), JarInJarMetadata.class);
|
||||||
if (metadata == null)
|
if (metadata == null)
|
||||||
throw new IOException("Invalid metadata file: " + jarInJarMetadata);
|
throw new IOException("Invalid metadata file: " + jarInJarMetadata);
|
||||||
|
|
||||||
@@ -246,11 +246,11 @@ public final class ForgeNewModMetadata {
|
|||||||
|
|
||||||
embeddedModFiles = new ArrayList<>();
|
embeddedModFiles = new ArrayList<>();
|
||||||
for (EmbeddedJarMetadata jar : metadata.jars) {
|
for (EmbeddedJarMetadata jar : metadata.jars) {
|
||||||
Path path = fs.getPath(jar.path);
|
ZipArchiveEntry path = tree.getEntry(jar.path);
|
||||||
if (Files.isRegularFile(path)) {
|
if (path != null) {
|
||||||
embeddedModFiles.add(path);
|
embeddedModFiles.add(path);
|
||||||
} else {
|
} else {
|
||||||
LOG.warning("Missing embedded-dependencies-mod: " + path);
|
LOG.warning("Missing embedded-dependencies-mod: " + jar.path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -262,10 +262,10 @@ public final class ForgeNewModMetadata {
|
|||||||
|
|
||||||
Path tempFile = Files.createTempFile("hmcl-", ".zip");
|
Path tempFile = Files.createTempFile("hmcl-", ".zip");
|
||||||
try {
|
try {
|
||||||
for (Path embeddedModFile : embeddedModFiles) {
|
for (ZipArchiveEntry embeddedModFile : embeddedModFiles) {
|
||||||
Files.copy(embeddedModFile, tempFile, StandardCopyOption.REPLACE_EXISTING);
|
tree.extractTo(embeddedModFile, tempFile);
|
||||||
try (FileSystem embeddedFs = CompressingUtils.createReadOnlyZipFileSystem(tempFile)) {
|
try (ZipFileTree embeddedTree = CompressingUtils.openZipTree(tempFile)) {
|
||||||
return fromFile(modManager, modFile, embeddedFs, modLoaderType);
|
return fromFile(modManager, modFile, embeddedTree, modLoaderType);
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,16 +21,16 @@ import com.google.gson.JsonParseException;
|
|||||||
import com.google.gson.annotations.SerializedName;
|
import com.google.gson.annotations.SerializedName;
|
||||||
import com.google.gson.stream.JsonReader;
|
import com.google.gson.stream.JsonReader;
|
||||||
import com.google.gson.stream.JsonToken;
|
import com.google.gson.stream.JsonToken;
|
||||||
|
import kala.compress.archivers.zip.ZipArchiveEntry;
|
||||||
import org.jackhuang.hmcl.mod.LocalModFile;
|
import org.jackhuang.hmcl.mod.LocalModFile;
|
||||||
import org.jackhuang.hmcl.mod.ModLoaderType;
|
import org.jackhuang.hmcl.mod.ModLoaderType;
|
||||||
import org.jackhuang.hmcl.mod.ModManager;
|
import org.jackhuang.hmcl.mod.ModManager;
|
||||||
import org.jackhuang.hmcl.util.Immutable;
|
import org.jackhuang.hmcl.util.Immutable;
|
||||||
import org.jackhuang.hmcl.util.StringUtils;
|
import org.jackhuang.hmcl.util.StringUtils;
|
||||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||||
|
import org.jackhuang.hmcl.util.tree.ZipFileTree;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.FileSystem;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -123,14 +123,14 @@ public final class ForgeOldModMetadata {
|
|||||||
return authors;
|
return authors;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LocalModFile fromFile(ModManager modManager, Path modFile, FileSystem fs) throws IOException, JsonParseException {
|
public static LocalModFile fromFile(ModManager modManager, Path modFile, ZipFileTree tree) throws IOException, JsonParseException {
|
||||||
Path mcmod = fs.getPath("mcmod.info");
|
ZipArchiveEntry mcmod = tree.getEntry("mcmod.info");
|
||||||
if (Files.notExists(mcmod))
|
if (mcmod == null)
|
||||||
throw new IOException("File " + modFile + " is not a Forge mod.");
|
throw new IOException("File " + modFile + " is not a Forge mod.");
|
||||||
|
|
||||||
List<ForgeOldModMetadata> modList;
|
List<ForgeOldModMetadata> modList;
|
||||||
|
|
||||||
try (var reader = Files.newBufferedReader(mcmod);
|
try (var reader = tree.getBufferedReader(mcmod);
|
||||||
var jsonReader = new JsonReader(reader)) {
|
var jsonReader = new JsonReader(reader)) {
|
||||||
JsonToken firstToken = jsonReader.peek();
|
JsonToken firstToken = jsonReader.peek();
|
||||||
|
|
||||||
|
|||||||
@@ -18,17 +18,16 @@
|
|||||||
package org.jackhuang.hmcl.mod.modinfo;
|
package org.jackhuang.hmcl.mod.modinfo;
|
||||||
|
|
||||||
import com.google.gson.JsonParseException;
|
import com.google.gson.JsonParseException;
|
||||||
|
import kala.compress.archivers.zip.ZipArchiveEntry;
|
||||||
import org.jackhuang.hmcl.mod.LocalModFile;
|
import org.jackhuang.hmcl.mod.LocalModFile;
|
||||||
import org.jackhuang.hmcl.mod.ModLoaderType;
|
import org.jackhuang.hmcl.mod.ModLoaderType;
|
||||||
import org.jackhuang.hmcl.mod.ModManager;
|
import org.jackhuang.hmcl.mod.ModManager;
|
||||||
import org.jackhuang.hmcl.util.Immutable;
|
import org.jackhuang.hmcl.util.Immutable;
|
||||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||||
|
import org.jackhuang.hmcl.util.tree.ZipFileTree;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.FileSystem;
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.zip.ZipEntry;
|
|
||||||
import java.util.zip.ZipFile;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -110,17 +109,15 @@ public final class LiteModMetadata {
|
|||||||
return updateURI;
|
return updateURI;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LocalModFile fromFile(ModManager modManager, Path modFile, FileSystem fs) throws IOException, JsonParseException {
|
public static LocalModFile fromFile(ModManager modManager, Path modFile, ZipFileTree tree) throws IOException, JsonParseException {
|
||||||
try (ZipFile zipFile = new ZipFile(modFile.toFile())) {
|
ZipArchiveEntry entry = tree.getEntry("litemod.json");
|
||||||
ZipEntry entry = zipFile.getEntry("litemod.json");
|
if (entry == null)
|
||||||
if (entry == null)
|
throw new IOException("File " + modFile + " is not a LiteLoader mod.");
|
||||||
throw new IOException("File " + modFile + "is not a LiteLoader mod.");
|
LiteModMetadata metadata = JsonUtils.fromJsonFully(tree.getInputStream(entry), LiteModMetadata.class);
|
||||||
LiteModMetadata metadata = JsonUtils.fromJsonFully(zipFile.getInputStream(entry), LiteModMetadata.class);
|
if (metadata == null)
|
||||||
if (metadata == null)
|
throw new IOException("Mod " + modFile + " `litemod.json` is malformed.");
|
||||||
throw new IOException("Mod " + modFile + " `litemod.json` is malformed.");
|
return new LocalModFile(modManager, modManager.getLocalMod(metadata.getName(), ModLoaderType.LITE_LOADER), modFile, metadata.getName(), new LocalModFile.Description(metadata.getDescription()), metadata.getAuthor(),
|
||||||
return new LocalModFile(modManager, modManager.getLocalMod(metadata.getName(), ModLoaderType.LITE_LOADER), modFile, metadata.getName(), new LocalModFile.Description(metadata.getDescription()), metadata.getAuthor(),
|
metadata.getVersion(), metadata.getGameVersion(), metadata.getUpdateURI(), "");
|
||||||
metadata.getVersion(), metadata.getGameVersion(), metadata.getUpdateURI(), "");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ package org.jackhuang.hmcl.mod.modinfo;
|
|||||||
import com.google.gson.*;
|
import com.google.gson.*;
|
||||||
import com.google.gson.annotations.JsonAdapter;
|
import com.google.gson.annotations.JsonAdapter;
|
||||||
import com.google.gson.annotations.SerializedName;
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
import kala.compress.archivers.zip.ZipArchiveEntry;
|
||||||
import org.jackhuang.hmcl.mod.LocalModFile;
|
import org.jackhuang.hmcl.mod.LocalModFile;
|
||||||
import org.jackhuang.hmcl.mod.ModLoaderType;
|
import org.jackhuang.hmcl.mod.ModLoaderType;
|
||||||
import org.jackhuang.hmcl.mod.ModManager;
|
import org.jackhuang.hmcl.mod.ModManager;
|
||||||
@@ -29,11 +30,10 @@ import org.jackhuang.hmcl.util.gson.JsonSerializable;
|
|||||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||||
import org.jackhuang.hmcl.util.gson.Validation;
|
import org.jackhuang.hmcl.util.gson.Validation;
|
||||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||||
|
import org.jackhuang.hmcl.util.tree.ZipFileTree;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.nio.file.FileSystem;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -183,11 +183,11 @@ public record PackMcMeta(@SerializedName("pack") PackInfo pack) implements Valid
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LocalModFile fromFile(ModManager modManager, Path modFile, FileSystem fs) throws IOException, JsonParseException {
|
public static LocalModFile fromFile(ModManager modManager, Path modFile, ZipFileTree tree) throws IOException, JsonParseException {
|
||||||
Path mcmod = fs.getPath("pack.mcmeta");
|
ZipArchiveEntry mcmod = tree.getEntry("pack.mcmeta");
|
||||||
if (Files.notExists(mcmod))
|
if (mcmod == null)
|
||||||
throw new IOException("File " + modFile + " is not a resource pack.");
|
throw new IOException("File " + modFile + " is not a resource pack.");
|
||||||
PackMcMeta metadata = JsonUtils.fromNonNullJson(Files.readString(mcmod), PackMcMeta.class);
|
PackMcMeta metadata = JsonUtils.fromNonNullJsonFully(tree.getInputStream(mcmod), PackMcMeta.class);
|
||||||
return new LocalModFile(
|
return new LocalModFile(
|
||||||
modManager,
|
modManager,
|
||||||
modManager.getLocalMod(FileUtils.getNameWithoutExtension(modFile), ModLoaderType.PACK),
|
modManager.getLocalMod(FileUtils.getNameWithoutExtension(modFile), ModLoaderType.PACK),
|
||||||
|
|||||||
@@ -2,15 +2,15 @@ package org.jackhuang.hmcl.mod.modinfo;
|
|||||||
|
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.google.gson.JsonParseException;
|
import com.google.gson.JsonParseException;
|
||||||
|
import kala.compress.archivers.zip.ZipArchiveEntry;
|
||||||
import org.jackhuang.hmcl.mod.LocalModFile;
|
import org.jackhuang.hmcl.mod.LocalModFile;
|
||||||
import org.jackhuang.hmcl.mod.ModLoaderType;
|
import org.jackhuang.hmcl.mod.ModLoaderType;
|
||||||
import org.jackhuang.hmcl.mod.ModManager;
|
import org.jackhuang.hmcl.mod.ModManager;
|
||||||
import org.jackhuang.hmcl.util.Immutable;
|
import org.jackhuang.hmcl.util.Immutable;
|
||||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||||
|
import org.jackhuang.hmcl.util.tree.ZipFileTree;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.FileSystem;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@@ -53,13 +53,13 @@ public final class QuiltModMetadata {
|
|||||||
this.quilt_loader = quiltLoader;
|
this.quilt_loader = quiltLoader;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LocalModFile fromFile(ModManager modManager, Path modFile, FileSystem fs) throws IOException, JsonParseException {
|
public static LocalModFile fromFile(ModManager modManager, Path modFile, ZipFileTree tree) throws IOException, JsonParseException {
|
||||||
Path path = fs.getPath("quilt.mod.json");
|
ZipArchiveEntry path = tree.getEntry("quilt.mod.json");
|
||||||
if (Files.notExists(path)) {
|
if (path == null) {
|
||||||
throw new IOException("File " + modFile + " is not a Quilt mod.");
|
throw new IOException("File " + modFile + " is not a Quilt mod.");
|
||||||
}
|
}
|
||||||
|
|
||||||
QuiltModMetadata root = JsonUtils.fromNonNullJson(Files.readString(path), QuiltModMetadata.class);
|
QuiltModMetadata root = JsonUtils.fromNonNullJsonFully(tree.getInputStream(path), QuiltModMetadata.class);
|
||||||
if (root.schema_version != 1) {
|
if (root.schema_version != 1) {
|
||||||
throw new IOException("File " + modFile + " is not a supported Quilt mod.");
|
throw new IOException("File " + modFile + " is not a supported Quilt mod.");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import kala.compress.archivers.zip.ZipArchiveEntry;
|
|||||||
import kala.compress.archivers.zip.ZipArchiveReader;
|
import kala.compress.archivers.zip.ZipArchiveReader;
|
||||||
import org.jackhuang.hmcl.util.Lang;
|
import org.jackhuang.hmcl.util.Lang;
|
||||||
import org.jackhuang.hmcl.util.platform.OperatingSystem;
|
import org.jackhuang.hmcl.util.platform.OperatingSystem;
|
||||||
|
import org.jackhuang.hmcl.util.tree.ZipFileTree;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
@@ -127,6 +128,10 @@ public final class CompressingUtils {
|
|||||||
throw new IOException("Cannot find suitable encoding for the zip.");
|
throw new IOException("Cannot find suitable encoding for the zip.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ZipFileTree openZipTree(Path zipFile) throws IOException {
|
||||||
|
return new ZipFileTree(openZipFile(zipFile));
|
||||||
|
}
|
||||||
|
|
||||||
public static ZipArchiveReader openZipFile(Path zipFile) throws IOException {
|
public static ZipArchiveReader openZipFile(Path zipFile) throws IOException {
|
||||||
ZipArchiveReader zipReader = new ZipArchiveReader(Files.newByteChannel(zipFile));
|
ZipArchiveReader zipReader = new ZipArchiveReader(Files.newByteChannel(zipFile));
|
||||||
Charset suitableEncoding;
|
Charset suitableEncoding;
|
||||||
|
|||||||
@@ -23,10 +23,7 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.annotations.UnmodifiableView;
|
import org.jetbrains.annotations.UnmodifiableView;
|
||||||
|
|
||||||
import java.io.Closeable;
|
import java.io.*;
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
@@ -152,6 +149,17 @@ public abstract class ArchiveFileTree<R, E extends ArchiveEntry> implements Clos
|
|||||||
return getInputStream(entry);
|
return getInputStream(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BufferedReader getBufferedReader(@NotNull E entry) throws IOException {
|
||||||
|
return new BufferedReader(new InputStreamReader(getInputStream(entry), StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull BufferedReader getBufferedReader(String entryPath) throws IOException {
|
||||||
|
E entry = getEntry(entryPath);
|
||||||
|
if (entry == null)
|
||||||
|
throw new FileNotFoundException("Entry not found: " + entryPath);
|
||||||
|
return getBufferedReader(entry);
|
||||||
|
}
|
||||||
|
|
||||||
public byte[] readBinaryEntry(@NotNull E entry) throws IOException {
|
public byte[] readBinaryEntry(@NotNull E entry) throws IOException {
|
||||||
try (InputStream input = getInputStream(entry)) {
|
try (InputStream input = getInputStream(entry)) {
|
||||||
return input.readAllBytes();
|
return input.readAllBytes();
|
||||||
|
|||||||
Reference in New Issue
Block a user