Auto detect encoding of compressed packs
This commit is contained in:
@@ -73,7 +73,7 @@ public final class HMCLModpackInstallTask extends Task {
|
|||||||
}
|
}
|
||||||
} catch (JsonParseException | IOException ignore) {
|
} catch (JsonParseException | IOException ignore) {
|
||||||
}
|
}
|
||||||
dependents.add(new ModpackInstallTask<>(zipFile, run, "/minecraft", it -> !"pack.json".equals(it), config));
|
dependents.add(new ModpackInstallTask<>(zipFile, run, modpack.getEncoding(), "/minecraft", it -> !"pack.json".equals(it), config));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -91,7 +91,7 @@ public final class HMCLModpackInstallTask extends Task {
|
|||||||
String json = CompressingUtils.readTextZipEntry(zipFile, "minecraft/pack.json");
|
String json = CompressingUtils.readTextZipEntry(zipFile, "minecraft/pack.json");
|
||||||
Version version = JsonUtils.GSON.fromJson(json, Version.class).setId(name).setJar(null);
|
Version version = JsonUtils.GSON.fromJson(json, Version.class).setId(name).setJar(null);
|
||||||
dependencies.add(new VersionJsonSaveTask(repository, version));
|
dependencies.add(new VersionJsonSaveTask(repository, version));
|
||||||
dependencies.add(new MinecraftInstanceTask<>(zipFile, "/minecraft", modpack, MODPACK_TYPE, repository.getModpackConfiguration(name)));
|
dependencies.add(new MinecraftInstanceTask<>(zipFile, modpack.getEncoding(), "/minecraft", modpack, MODPACK_TYPE, repository.getModpackConfiguration(name)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final String MODPACK_TYPE = "HMCL";
|
public static final String MODPACK_TYPE = "HMCL";
|
||||||
|
|||||||
@@ -24,8 +24,9 @@ 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.io.CompressingUtils;
|
import org.jackhuang.hmcl.util.io.CompressingUtils;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -75,14 +76,15 @@ public final class HMCLModpackManager {
|
|||||||
* Read the manifest in a HMCL modpack.
|
* Read the manifest in a HMCL modpack.
|
||||||
*
|
*
|
||||||
* @param file a HMCL modpack file.
|
* @param file a HMCL modpack file.
|
||||||
|
* @param encoding encoding of modpack zip file.
|
||||||
* @throws IOException if the file is not a valid zip file.
|
* @throws IOException if the file is not a valid zip file.
|
||||||
* @throws JsonParseException if the manifest.json is missing or malformed.
|
* @throws JsonParseException if the manifest.json is missing or malformed.
|
||||||
* @return the manifest of HMCL modpack.
|
* @return the manifest of HMCL modpack.
|
||||||
*/
|
*/
|
||||||
public static Modpack readHMCLModpackManifest(File file) throws IOException, JsonParseException {
|
public static Modpack readHMCLModpackManifest(Path file, Charset encoding) throws IOException, JsonParseException {
|
||||||
String manifestJson = CompressingUtils.readTextZipEntry(file, "modpack.json");
|
String manifestJson = CompressingUtils.readTextZipEntry(file, "modpack.json", encoding);
|
||||||
Modpack manifest = JsonUtils.fromNonNullJson(manifestJson, Modpack.class);
|
Modpack manifest = JsonUtils.fromNonNullJson(manifestJson, Modpack.class).setEncoding(encoding);
|
||||||
String gameJson = CompressingUtils.readTextZipEntry(file, "minecraft/pack.json");
|
String gameJson = CompressingUtils.readTextZipEntry(file, "minecraft/pack.json", encoding);
|
||||||
Version game = JsonUtils.fromNonNullJson(gameJson, Version.class);
|
Version game = JsonUtils.fromNonNullJson(gameJson, Version.class);
|
||||||
if (game.getJar() == null)
|
if (game.getJar() == null)
|
||||||
if (StringUtils.isBlank(manifest.getVersion()))
|
if (StringUtils.isBlank(manifest.getVersion()))
|
||||||
|
|||||||
@@ -23,10 +23,8 @@ import org.jackhuang.hmcl.mod.*;
|
|||||||
import org.jackhuang.hmcl.setting.EnumGameDirectory;
|
import org.jackhuang.hmcl.setting.EnumGameDirectory;
|
||||||
import org.jackhuang.hmcl.setting.Profile;
|
import org.jackhuang.hmcl.setting.Profile;
|
||||||
import org.jackhuang.hmcl.setting.VersionSetting;
|
import org.jackhuang.hmcl.setting.VersionSetting;
|
||||||
import org.jackhuang.hmcl.task.FinalizedCallback;
|
|
||||||
import org.jackhuang.hmcl.task.Schedulers;
|
import org.jackhuang.hmcl.task.Schedulers;
|
||||||
import org.jackhuang.hmcl.task.Task;
|
import org.jackhuang.hmcl.task.Task;
|
||||||
import org.jackhuang.hmcl.util.AutoTypingMap;
|
|
||||||
import org.jackhuang.hmcl.util.Lang;
|
import org.jackhuang.hmcl.util.Lang;
|
||||||
import org.jackhuang.hmcl.util.function.ExceptionalConsumer;
|
import org.jackhuang.hmcl.util.function.ExceptionalConsumer;
|
||||||
import org.jackhuang.hmcl.util.function.ExceptionalRunnable;
|
import org.jackhuang.hmcl.util.function.ExceptionalRunnable;
|
||||||
@@ -36,26 +34,28 @@ import org.jackhuang.hmcl.util.io.FileUtils;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
public final class ModpackHelper {
|
public final class ModpackHelper {
|
||||||
private ModpackHelper() {}
|
private ModpackHelper() {}
|
||||||
|
|
||||||
public static Modpack readModpackManifest(File file) throws UnsupportedModpackException {
|
public static Modpack readModpackManifest(Path file, Charset charset) throws UnsupportedModpackException {
|
||||||
try {
|
try {
|
||||||
return CurseManifest.readCurseForgeModpackManifest(file);
|
return CurseManifest.readCurseForgeModpackManifest(file, charset);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// ignore it, not a valid CurseForge modpack.
|
// ignore it, not a valid CurseForge modpack.
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return HMCLModpackManager.readHMCLModpackManifest(file);
|
return HMCLModpackManager.readHMCLModpackManifest(file, charset);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// ignore it, not a valid HMCL modpack.
|
// ignore it, not a valid HMCL modpack.
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return MultiMCInstanceConfiguration.readMultiMCModpackManifest(file);
|
return MultiMCInstanceConfiguration.readMultiMCModpackManifest(file, charset);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// ignore it, not a valid MultiMC modpack.
|
// ignore it, not a valid MultiMC modpack.
|
||||||
}
|
}
|
||||||
@@ -109,32 +109,32 @@ public final class ModpackHelper {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (modpack.getManifest() instanceof CurseManifest)
|
if (modpack.getManifest() instanceof CurseManifest)
|
||||||
return new CurseInstallTask(profile.getDependency(), zipFile, ((CurseManifest) modpack.getManifest()), name)
|
return new CurseInstallTask(profile.getDependency(), zipFile, modpack, ((CurseManifest) modpack.getManifest()), name)
|
||||||
.finalized(Schedulers.defaultScheduler(), ExceptionalConsumer.fromRunnable(success), failure);
|
.finalized(Schedulers.defaultScheduler(), ExceptionalConsumer.fromRunnable(success), failure);
|
||||||
else if (modpack.getManifest() instanceof HMCLModpackManifest)
|
else if (modpack.getManifest() instanceof HMCLModpackManifest)
|
||||||
return new HMCLModpackInstallTask(profile, zipFile, modpack, name)
|
return new HMCLModpackInstallTask(profile, zipFile, modpack, name)
|
||||||
.finalized(Schedulers.defaultScheduler(), ExceptionalConsumer.fromRunnable(success), failure);
|
.finalized(Schedulers.defaultScheduler(), ExceptionalConsumer.fromRunnable(success), failure);
|
||||||
else if (modpack.getManifest() instanceof MultiMCInstanceConfiguration)
|
else if (modpack.getManifest() instanceof MultiMCInstanceConfiguration)
|
||||||
return new MultiMCModpackInstallTask(profile.getDependency(), zipFile, ((MultiMCInstanceConfiguration) modpack.getManifest()), name)
|
return new MultiMCModpackInstallTask(profile.getDependency(), zipFile, modpack, ((MultiMCInstanceConfiguration) modpack.getManifest()), name)
|
||||||
.finalized(Schedulers.defaultScheduler(), ExceptionalConsumer.fromRunnable(success), failure)
|
.finalized(Schedulers.defaultScheduler(), ExceptionalConsumer.fromRunnable(success), failure)
|
||||||
.then(new MultiMCInstallVersionSettingTask(profile, ((MultiMCInstanceConfiguration) modpack.getManifest()), name));
|
.then(new MultiMCInstallVersionSettingTask(profile, ((MultiMCInstanceConfiguration) modpack.getManifest()), name));
|
||||||
else throw new IllegalStateException("Unrecognized modpack: " + modpack);
|
else throw new IllegalStateException("Unrecognized modpack: " + modpack);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Task getUpdateTask(Profile profile, File zipFile, String name, ModpackConfiguration<?> configuration) throws UnsupportedModpackException, MismatchedModpackTypeException {
|
public static Task getUpdateTask(Profile profile, File zipFile, Charset charset, String name, ModpackConfiguration<?> configuration) throws UnsupportedModpackException, MismatchedModpackTypeException {
|
||||||
Modpack modpack = ModpackHelper.readModpackManifest(zipFile);
|
Modpack modpack = ModpackHelper.readModpackManifest(zipFile.toPath(), charset);
|
||||||
|
|
||||||
switch (configuration.getType()) {
|
switch (configuration.getType()) {
|
||||||
case CurseInstallTask.MODPACK_TYPE:
|
case CurseInstallTask.MODPACK_TYPE:
|
||||||
if (!(modpack.getManifest() instanceof CurseManifest))
|
if (!(modpack.getManifest() instanceof CurseManifest))
|
||||||
throw new MismatchedModpackTypeException(CurseInstallTask.MODPACK_TYPE, getManifestType(modpack.getManifest()));
|
throw new MismatchedModpackTypeException(CurseInstallTask.MODPACK_TYPE, getManifestType(modpack.getManifest()));
|
||||||
|
|
||||||
return new CurseInstallTask(profile.getDependency(), zipFile, (CurseManifest) modpack.getManifest(), name);
|
return new CurseInstallTask(profile.getDependency(), zipFile, modpack, (CurseManifest) modpack.getManifest(), name);
|
||||||
case MultiMCModpackInstallTask.MODPACK_TYPE:
|
case MultiMCModpackInstallTask.MODPACK_TYPE:
|
||||||
if (!(modpack.getManifest() instanceof MultiMCInstanceConfiguration))
|
if (!(modpack.getManifest() instanceof MultiMCInstanceConfiguration))
|
||||||
throw new MismatchedModpackTypeException(MultiMCModpackInstallTask.MODPACK_TYPE, getManifestType(modpack.getManifest()));
|
throw new MismatchedModpackTypeException(MultiMCModpackInstallTask.MODPACK_TYPE, getManifestType(modpack.getManifest()));
|
||||||
|
|
||||||
return new MultiMCModpackInstallTask(profile.getDependency(), zipFile, (MultiMCInstanceConfiguration) modpack.getManifest(), name);
|
return new MultiMCModpackInstallTask(profile.getDependency(), zipFile, modpack, (MultiMCInstanceConfiguration) modpack.getManifest(), name);
|
||||||
case HMCLModpackInstallTask.MODPACK_TYPE:
|
case HMCLModpackInstallTask.MODPACK_TYPE:
|
||||||
if (!(modpack.getManifest() instanceof HMCLModpackManifest))
|
if (!(modpack.getManifest() instanceof HMCLModpackManifest))
|
||||||
throw new MismatchedModpackTypeException(HMCLModpackInstallTask.MODPACK_TYPE, getManifestType(modpack.getManifest()));
|
throw new MismatchedModpackTypeException(HMCLModpackInstallTask.MODPACK_TYPE, getManifestType(modpack.getManifest()));
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import org.jackhuang.hmcl.event.RefreshedVersionsEvent;
|
|||||||
import org.jackhuang.hmcl.game.HMCLGameRepository;
|
import org.jackhuang.hmcl.game.HMCLGameRepository;
|
||||||
import org.jackhuang.hmcl.game.ModpackHelper;
|
import org.jackhuang.hmcl.game.ModpackHelper;
|
||||||
import org.jackhuang.hmcl.mod.Modpack;
|
import org.jackhuang.hmcl.mod.Modpack;
|
||||||
import org.jackhuang.hmcl.mod.UnsupportedModpackException;
|
|
||||||
import org.jackhuang.hmcl.setting.Accounts;
|
import org.jackhuang.hmcl.setting.Accounts;
|
||||||
import org.jackhuang.hmcl.setting.Profile;
|
import org.jackhuang.hmcl.setting.Profile;
|
||||||
import org.jackhuang.hmcl.setting.Profiles;
|
import org.jackhuang.hmcl.setting.Profiles;
|
||||||
@@ -41,6 +40,7 @@ import org.jackhuang.hmcl.ui.construct.DialogCloseEvent;
|
|||||||
import org.jackhuang.hmcl.ui.profile.ProfileAdvancedListItem;
|
import org.jackhuang.hmcl.ui.profile.ProfileAdvancedListItem;
|
||||||
import org.jackhuang.hmcl.ui.versions.GameAdvancedListItem;
|
import org.jackhuang.hmcl.ui.versions.GameAdvancedListItem;
|
||||||
import org.jackhuang.hmcl.ui.versions.Versions;
|
import org.jackhuang.hmcl.ui.versions.Versions;
|
||||||
|
import org.jackhuang.hmcl.util.io.CompressingUtils;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
@@ -111,7 +111,6 @@ public final class LeftPaneController extends AdvancedListBox {
|
|||||||
// ====
|
// ====
|
||||||
|
|
||||||
private boolean checkedModpack = false;
|
private boolean checkedModpack = false;
|
||||||
private static boolean showNewAccount = true;
|
|
||||||
|
|
||||||
private void onRefreshedVersions(HMCLGameRepository repository) {
|
private void onRefreshedVersions(HMCLGameRepository repository) {
|
||||||
JFXUtilities.runInFX(() -> {
|
JFXUtilities.runInFX(() -> {
|
||||||
@@ -121,27 +120,24 @@ public final class LeftPaneController extends AdvancedListBox {
|
|||||||
if (repository.getVersionCount() == 0) {
|
if (repository.getVersionCount() == 0) {
|
||||||
File modpackFile = new File("modpack.zip").getAbsoluteFile();
|
File modpackFile = new File("modpack.zip").getAbsoluteFile();
|
||||||
if (modpackFile.exists()) {
|
if (modpackFile.exists()) {
|
||||||
try {
|
Task.ofResult("encoding", () -> CompressingUtils.findSuitableEncoding(modpackFile.toPath()))
|
||||||
AtomicReference<Region> region = new AtomicReference<>();
|
.then(Task.ofResult("modpack", var -> ModpackHelper.readModpackManifest(modpackFile.toPath(), var.get("encoding"))))
|
||||||
Modpack modpack = ModpackHelper.readModpackManifest(modpackFile);
|
.then(Task.of(var -> {
|
||||||
TaskExecutor executor = ModpackHelper.getInstallTask(repository.getProfile(), modpackFile, modpack.getName(), modpack)
|
AtomicReference<Region> region = new AtomicReference<>();
|
||||||
.with(Task.of(Schedulers.javafx(), () -> {
|
Modpack modpack = var.get("modpack");
|
||||||
region.get().fireEvent(new DialogCloseEvent());
|
TaskExecutor executor = ModpackHelper.getInstallTask(repository.getProfile(), modpackFile, modpack.getName(), modpack)
|
||||||
checkAccount();
|
.with(Task.of(Schedulers.javafx(), () -> {
|
||||||
})).executor();
|
region.get().fireEvent(new DialogCloseEvent());
|
||||||
region.set(Controllers.taskDialog(executor, i18n("modpack.installing"), ""));
|
checkAccount();
|
||||||
executor.start();
|
})).executor();
|
||||||
showNewAccount = false;
|
region.set(Controllers.taskDialog(executor, i18n("modpack.installing"), ""));
|
||||||
} catch (UnsupportedModpackException ignore) {
|
executor.start();
|
||||||
}
|
})).start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showNewAccount) {
|
checkAccount();
|
||||||
showNewAccount = false;
|
|
||||||
checkAccount();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,16 +27,19 @@ import javafx.scene.layout.StackPane;
|
|||||||
import javafx.stage.FileChooser;
|
import javafx.stage.FileChooser;
|
||||||
import org.jackhuang.hmcl.game.ModpackHelper;
|
import org.jackhuang.hmcl.game.ModpackHelper;
|
||||||
import org.jackhuang.hmcl.mod.Modpack;
|
import org.jackhuang.hmcl.mod.Modpack;
|
||||||
import org.jackhuang.hmcl.mod.UnsupportedModpackException;
|
|
||||||
import org.jackhuang.hmcl.setting.Profile;
|
import org.jackhuang.hmcl.setting.Profile;
|
||||||
|
import org.jackhuang.hmcl.task.Schedulers;
|
||||||
|
import org.jackhuang.hmcl.task.Task;
|
||||||
import org.jackhuang.hmcl.ui.Controllers;
|
import org.jackhuang.hmcl.ui.Controllers;
|
||||||
import org.jackhuang.hmcl.ui.FXUtils;
|
import org.jackhuang.hmcl.ui.FXUtils;
|
||||||
import org.jackhuang.hmcl.ui.WebStage;
|
import org.jackhuang.hmcl.ui.WebStage;
|
||||||
import org.jackhuang.hmcl.ui.construct.MessageBox;
|
import org.jackhuang.hmcl.ui.construct.MessageBox;
|
||||||
|
import org.jackhuang.hmcl.ui.construct.SpinnerPane;
|
||||||
import org.jackhuang.hmcl.ui.construct.Validator;
|
import org.jackhuang.hmcl.ui.construct.Validator;
|
||||||
import org.jackhuang.hmcl.ui.wizard.WizardController;
|
import org.jackhuang.hmcl.ui.wizard.WizardController;
|
||||||
import org.jackhuang.hmcl.ui.wizard.WizardPage;
|
import org.jackhuang.hmcl.ui.wizard.WizardPage;
|
||||||
import org.jackhuang.hmcl.util.StringUtils;
|
import org.jackhuang.hmcl.util.StringUtils;
|
||||||
|
import org.jackhuang.hmcl.util.io.CompressingUtils;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -71,6 +74,9 @@ public final class ModpackPage extends StackPane implements WizardPage {
|
|||||||
@FXML
|
@FXML
|
||||||
private JFXButton btnInstall;
|
private JFXButton btnInstall;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private SpinnerPane spinnerPane;
|
||||||
|
|
||||||
public ModpackPage(WizardController controller) {
|
public ModpackPage(WizardController controller) {
|
||||||
this.controller = controller;
|
this.controller = controller;
|
||||||
|
|
||||||
@@ -96,24 +102,28 @@ public final class ModpackPage extends StackPane implements WizardPage {
|
|||||||
controller.getSettings().put(MODPACK_FILE, selectedFile);
|
controller.getSettings().put(MODPACK_FILE, selectedFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
spinnerPane.showSpinner();
|
||||||
manifest = ModpackHelper.readModpackManifest(selectedFile);
|
Task.ofResult("encoding", () -> CompressingUtils.findSuitableEncoding(selectedFile.toPath()))
|
||||||
controller.getSettings().put(MODPACK_MANIFEST, manifest);
|
.then(Task.ofResult("manifest", var ->
|
||||||
lblName.setText(manifest.getName());
|
manifest = ModpackHelper.readModpackManifest(selectedFile.toPath(), var.get("encoding"))))
|
||||||
lblVersion.setText(manifest.getVersion());
|
.finalized(Schedulers.javafx(), var -> {
|
||||||
lblAuthor.setText(manifest.getAuthor());
|
spinnerPane.hideSpinner();
|
||||||
txtModpackName.setText(manifest.getName() + (StringUtils.isBlank(manifest.getVersion()) ? "" : "-" + manifest.getVersion()));
|
controller.getSettings().put(MODPACK_MANIFEST, manifest);
|
||||||
|
lblName.setText(manifest.getName());
|
||||||
|
lblVersion.setText(manifest.getVersion());
|
||||||
|
lblAuthor.setText(manifest.getAuthor());
|
||||||
|
txtModpackName.setText(manifest.getName() + (StringUtils.isBlank(manifest.getVersion()) ? "" : "-" + manifest.getVersion()));
|
||||||
|
|
||||||
lblModpackLocation.setText(selectedFile.getAbsolutePath());
|
lblModpackLocation.setText(selectedFile.getAbsolutePath());
|
||||||
txtModpackName.getValidators().addAll(
|
txtModpackName.getValidators().addAll(
|
||||||
new Validator(i18n("install.new_game.already_exists"), str -> !profile.getRepository().hasVersion(str) && StringUtils.isNotBlank(str)),
|
new Validator(i18n("install.new_game.already_exists"), str -> !profile.getRepository().hasVersion(str) && StringUtils.isNotBlank(str)),
|
||||||
new Validator(i18n("version.forbidden_name"), str -> !profile.getRepository().forbidsVersion(str))
|
new Validator(i18n("version.forbidden_name"), str -> !profile.getRepository().forbidsVersion(str))
|
||||||
);
|
);
|
||||||
txtModpackName.textProperty().addListener(e -> btnInstall.setDisable(!txtModpackName.validate()));
|
txtModpackName.textProperty().addListener(e -> btnInstall.setDisable(!txtModpackName.validate()));
|
||||||
} catch (UnsupportedModpackException e) {
|
}, e -> {
|
||||||
Controllers.dialog(i18n("modpack.task.install.error"), i18n("message.error"), MessageBox.ERROR_MESSAGE);
|
Controllers.dialog(i18n("modpack.task.install.error"), i18n("message.error"), MessageBox.ERROR_MESSAGE);
|
||||||
Platform.runLater(controller::onEnd);
|
Platform.runLater(controller::onEnd);
|
||||||
}
|
}).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import org.jackhuang.hmcl.ui.wizard.WizardProvider;
|
|||||||
import org.jackhuang.hmcl.util.io.Zipper;
|
import org.jackhuang.hmcl.util.io.Zipper;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -74,6 +75,7 @@ public final class ExportWizardProvider implements WizardProvider {
|
|||||||
(String) settings.get(ModpackInfoPage.MODPACK_VERSION),
|
(String) settings.get(ModpackInfoPage.MODPACK_VERSION),
|
||||||
null,
|
null,
|
||||||
(String) settings.get(ModpackInfoPage.MODPACK_DESCRIPTION),
|
(String) settings.get(ModpackInfoPage.MODPACK_DESCRIPTION),
|
||||||
|
StandardCharsets.UTF_8,
|
||||||
null
|
null
|
||||||
), tempModpack);
|
), tempModpack);
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import org.jackhuang.hmcl.ui.construct.DialogCloseEvent;
|
|||||||
import org.jackhuang.hmcl.ui.construct.MessageBox;
|
import org.jackhuang.hmcl.ui.construct.MessageBox;
|
||||||
import org.jackhuang.hmcl.ui.export.ExportWizardProvider;
|
import org.jackhuang.hmcl.ui.export.ExportWizardProvider;
|
||||||
import org.jackhuang.hmcl.util.Logging;
|
import org.jackhuang.hmcl.util.Logging;
|
||||||
|
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.platform.OperatingSystem;
|
import org.jackhuang.hmcl.util.platform.OperatingSystem;
|
||||||
|
|
||||||
@@ -86,19 +87,23 @@ public class Versions {
|
|||||||
chooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(i18n("modpack"), "*.zip"));
|
chooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(i18n("modpack"), "*.zip"));
|
||||||
File selectedFile = chooser.showOpenDialog(Controllers.getStage());
|
File selectedFile = chooser.showOpenDialog(Controllers.getStage());
|
||||||
if (selectedFile != null) {
|
if (selectedFile != null) {
|
||||||
AtomicReference<Region> region = new AtomicReference<>();
|
Task.ofResult("encoding", () -> CompressingUtils.findSuitableEncoding(selectedFile.toPath()))
|
||||||
try {
|
.then(Task.of(Schedulers.javafx(), var -> {
|
||||||
TaskExecutor executor = ModpackHelper.getUpdateTask(profile, selectedFile, version, ModpackHelper.readModpackConfiguration(profile.getRepository().getModpackConfiguration(version)))
|
AtomicReference<Region> region = new AtomicReference<>();
|
||||||
.then(Task.of(Schedulers.javafx(), () -> region.get().fireEvent(new DialogCloseEvent()))).executor();
|
try {
|
||||||
region.set(Controllers.taskDialog(executor, i18n("modpack.update"), ""));
|
TaskExecutor executor = ModpackHelper.getUpdateTask(profile, selectedFile, var.get("encoding"), version, ModpackHelper.readModpackConfiguration(profile.getRepository().getModpackConfiguration(version)))
|
||||||
executor.start();
|
.then(Task.of(Schedulers.javafx(), () -> region.get().fireEvent(new DialogCloseEvent()))).executor();
|
||||||
} catch (UnsupportedModpackException e) {
|
region.set(Controllers.taskDialog(executor, i18n("modpack.update"), ""));
|
||||||
Controllers.dialog(i18n("modpack.unsupported"), i18n("message.error"), MessageBox.ERROR_MESSAGE);
|
executor.start();
|
||||||
} catch (MismatchedModpackTypeException e) {
|
} catch (UnsupportedModpackException e) {
|
||||||
Controllers.dialog(i18n("modpack.mismatched_type"), i18n("message.error"), MessageBox.ERROR_MESSAGE);
|
Controllers.dialog(i18n("modpack.unsupported"), i18n("message.error"), MessageBox.ERROR_MESSAGE);
|
||||||
} catch (IOException e) {
|
} catch (MismatchedModpackTypeException e) {
|
||||||
Controllers.dialog(i18n("modpack.invalid"), i18n("message.error"), MessageBox.ERROR_MESSAGE);
|
Controllers.dialog(i18n("modpack.mismatched_type"), i18n("message.error"), MessageBox.ERROR_MESSAGE);
|
||||||
}
|
} catch (IOException e) {
|
||||||
|
Controllers.dialog(i18n("modpack.invalid"), i18n("message.error"), MessageBox.ERROR_MESSAGE);
|
||||||
|
}
|
||||||
|
})).start();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,12 +7,14 @@
|
|||||||
<?import javafx.scene.layout.*?>
|
<?import javafx.scene.layout.*?>
|
||||||
<?import org.jackhuang.hmcl.ui.construct.ComponentList?>
|
<?import org.jackhuang.hmcl.ui.construct.ComponentList?>
|
||||||
<?import org.jackhuang.hmcl.ui.FXUtils?>
|
<?import org.jackhuang.hmcl.ui.FXUtils?>
|
||||||
|
<?import org.jackhuang.hmcl.ui.construct.SpinnerPane?>
|
||||||
<fx:root xmlns="http://javafx.com/javafx"
|
<fx:root xmlns="http://javafx.com/javafx"
|
||||||
xmlns:fx="http://javafx.com/fxml"
|
xmlns:fx="http://javafx.com/fxml"
|
||||||
type="StackPane">
|
type="StackPane">
|
||||||
<fx:define>
|
<fx:define>
|
||||||
<Insets fx:id="insets" bottom="12" />
|
<Insets fx:id="insets" bottom="12" />
|
||||||
</fx:define>
|
</fx:define>
|
||||||
|
<SpinnerPane fx:id="spinnerPane">
|
||||||
<VBox fx:id="borderPane" alignment="CENTER" FXUtils.limitWidth="500">
|
<VBox fx:id="borderPane" alignment="CENTER" FXUtils.limitWidth="500">
|
||||||
<HBox style="-fx-padding: 0 0 16 5;"><Label text="%modpack.task.install" /></HBox>
|
<HBox style="-fx-padding: 0 0 16 5;"><Label text="%modpack.task.install" /></HBox>
|
||||||
<ComponentList>
|
<ComponentList>
|
||||||
@@ -27,4 +29,5 @@
|
|||||||
</BorderPane>
|
</BorderPane>
|
||||||
</ComponentList>
|
</ComponentList>
|
||||||
</VBox>
|
</VBox>
|
||||||
|
</SpinnerPane>
|
||||||
</fx:root>
|
</fx:root>
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ public final class CurseInstallTask extends Task {
|
|||||||
private final DefaultDependencyManager dependencyManager;
|
private final DefaultDependencyManager dependencyManager;
|
||||||
private final DefaultGameRepository repository;
|
private final DefaultGameRepository repository;
|
||||||
private final File zipFile;
|
private final File zipFile;
|
||||||
|
private final Modpack modpack;
|
||||||
private final CurseManifest manifest;
|
private final CurseManifest manifest;
|
||||||
private final String name;
|
private final String name;
|
||||||
private final File run;
|
private final File run;
|
||||||
@@ -58,9 +59,10 @@ public final class CurseInstallTask extends Task {
|
|||||||
* @param name the new version name
|
* @param name the new version name
|
||||||
* @see CurseManifest#readCurseForgeModpackManifest
|
* @see CurseManifest#readCurseForgeModpackManifest
|
||||||
*/
|
*/
|
||||||
public CurseInstallTask(DefaultDependencyManager dependencyManager, File zipFile, CurseManifest manifest, String name) {
|
public CurseInstallTask(DefaultDependencyManager dependencyManager, File zipFile, Modpack modpack, CurseManifest manifest, String name) {
|
||||||
this.dependencyManager = dependencyManager;
|
this.dependencyManager = dependencyManager;
|
||||||
this.zipFile = zipFile;
|
this.zipFile = zipFile;
|
||||||
|
this.modpack = modpack;
|
||||||
this.manifest = manifest;
|
this.manifest = manifest;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.repository = dependencyManager.getGameRepository();
|
this.repository = dependencyManager.getGameRepository();
|
||||||
@@ -92,7 +94,7 @@ public final class CurseInstallTask extends Task {
|
|||||||
} catch (JsonParseException | IOException ignore) {
|
} catch (JsonParseException | IOException ignore) {
|
||||||
}
|
}
|
||||||
this.config = config;
|
this.config = config;
|
||||||
dependents.add(new ModpackInstallTask<>(zipFile, run, manifest.getOverrides(), any -> true, config));
|
dependents.add(new ModpackInstallTask<>(zipFile, run, modpack.getEncoding(), manifest.getOverrides(), any -> true, config));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -121,7 +123,7 @@ public final class CurseInstallTask extends Task {
|
|||||||
FileUtils.writeText(new File(root, "manifest.json"), JsonUtils.GSON.toJson(manifest));
|
FileUtils.writeText(new File(root, "manifest.json"), JsonUtils.GSON.toJson(manifest));
|
||||||
|
|
||||||
dependencies.add(new CurseCompletionTask(dependencyManager, name, manifest));
|
dependencies.add(new CurseCompletionTask(dependencyManager, name, manifest));
|
||||||
dependencies.add(new MinecraftInstanceTask<>(zipFile, manifest.getOverrides(), manifest, MODPACK_TYPE, repository.getModpackConfiguration(name)));
|
dependencies.add(new MinecraftInstanceTask<>(zipFile, modpack.getEncoding(), manifest.getOverrides(), manifest, MODPACK_TYPE, repository.getModpackConfiguration(name)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final String MODPACK_TYPE = "Curse";
|
public static final String MODPACK_TYPE = "Curse";
|
||||||
|
|||||||
@@ -19,13 +19,13 @@ package org.jackhuang.hmcl.mod;
|
|||||||
|
|
||||||
import com.google.gson.JsonParseException;
|
import com.google.gson.JsonParseException;
|
||||||
import com.google.gson.annotations.SerializedName;
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
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.io.CompressingUtils;
|
import org.jackhuang.hmcl.util.io.CompressingUtils;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -117,11 +117,11 @@ public final class CurseManifest {
|
|||||||
* @throws JsonParseException if the manifest.json is missing or malformed.
|
* @throws JsonParseException if the manifest.json is missing or malformed.
|
||||||
* @return the manifest.
|
* @return the manifest.
|
||||||
*/
|
*/
|
||||||
public static Modpack readCurseForgeModpackManifest(File f) throws IOException, JsonParseException {
|
public static Modpack readCurseForgeModpackManifest(Path zip, Charset encoding) throws IOException, JsonParseException {
|
||||||
String json = CompressingUtils.readTextZipEntry(f, "manifest.json");
|
String json = CompressingUtils.readTextZipEntry(zip, "manifest.json", encoding);
|
||||||
CurseManifest manifest = JsonUtils.fromNonNullJson(json, CurseManifest.class);
|
CurseManifest manifest = JsonUtils.fromNonNullJson(json, CurseManifest.class);
|
||||||
return new Modpack(manifest.getName(), manifest.getAuthor(), manifest.getVersion(), manifest.getMinecraft().getGameVersion(),
|
return new Modpack(manifest.getName(), manifest.getAuthor(), manifest.getVersion(), manifest.getMinecraft().getGameVersion(),
|
||||||
CompressingUtils.readTextZipEntryQuietly(f, "modlist.html").orElse( "No description"), manifest);
|
CompressingUtils.readTextZipEntryQuietly(zip, "modlist.html", encoding).orElse( "No description"), encoding, manifest);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final String MINECRAFT_MODPACK = "minecraftModpack";
|
public static final String MINECRAFT_MODPACK = "minecraftModpack";
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import org.jackhuang.hmcl.util.io.FileUtils;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
import java.nio.file.*;
|
import java.nio.file.*;
|
||||||
import java.nio.file.attribute.BasicFileAttributes;
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
@@ -35,13 +36,15 @@ import static org.jackhuang.hmcl.util.Hex.encodeHex;
|
|||||||
public final class MinecraftInstanceTask<T> extends Task {
|
public final class MinecraftInstanceTask<T> extends Task {
|
||||||
|
|
||||||
private final File zipFile;
|
private final File zipFile;
|
||||||
|
private final Charset encoding;
|
||||||
private final String subDirectory;
|
private final String subDirectory;
|
||||||
private final File jsonFile;
|
private final File jsonFile;
|
||||||
private final T manifest;
|
private final T manifest;
|
||||||
private final String type;
|
private final String type;
|
||||||
|
|
||||||
public MinecraftInstanceTask(File zipFile, String subDirectory, T manifest, String type, File jsonFile) {
|
public MinecraftInstanceTask(File zipFile, Charset encoding, String subDirectory, T manifest, String type, File jsonFile) {
|
||||||
this.zipFile = zipFile;
|
this.zipFile = zipFile;
|
||||||
|
this.encoding = encoding;
|
||||||
this.subDirectory = FileUtils.normalizePath(subDirectory);
|
this.subDirectory = FileUtils.normalizePath(subDirectory);
|
||||||
this.manifest = manifest;
|
this.manifest = manifest;
|
||||||
this.jsonFile = jsonFile;
|
this.jsonFile = jsonFile;
|
||||||
@@ -55,7 +58,7 @@ public final class MinecraftInstanceTask<T> extends Task {
|
|||||||
public void execute() throws Exception {
|
public void execute() throws Exception {
|
||||||
List<ModpackConfiguration.FileInformation> overrides = new LinkedList<>();
|
List<ModpackConfiguration.FileInformation> overrides = new LinkedList<>();
|
||||||
|
|
||||||
try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(zipFile.toPath())) {
|
try (FileSystem fs = CompressingUtils.readonly(zipFile.toPath()).setEncoding(encoding).build()) {
|
||||||
Path root = fs.getPath(subDirectory);
|
Path root = fs.getPath(subDirectory);
|
||||||
|
|
||||||
if (Files.exists(root))
|
if (Files.exists(root))
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.jackhuang.hmcl.mod;
|
package org.jackhuang.hmcl.mod;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author huangyuhui
|
* @author huangyuhui
|
||||||
@@ -27,18 +29,20 @@ public final class Modpack {
|
|||||||
private final String version;
|
private final String version;
|
||||||
private final String gameVersion;
|
private final String gameVersion;
|
||||||
private final String description;
|
private final String description;
|
||||||
|
private final transient Charset encoding;
|
||||||
private final Object manifest;
|
private final Object manifest;
|
||||||
|
|
||||||
public Modpack() {
|
public Modpack() {
|
||||||
this("", null, null, null, null, null);
|
this("", null, null, null, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Modpack(String name, String author, String version, String gameVersion, String description, Object manifest) {
|
public Modpack(String name, String author, String version, String gameVersion, String description, Charset encoding, Object manifest) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.author = author;
|
this.author = author;
|
||||||
this.version = version;
|
this.version = version;
|
||||||
this.gameVersion = gameVersion;
|
this.gameVersion = gameVersion;
|
||||||
this.description = description;
|
this.description = description;
|
||||||
|
this.encoding = encoding;
|
||||||
this.manifest = manifest;
|
this.manifest = manifest;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,18 +63,26 @@ public final class Modpack {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Modpack setGameVersion(String gameVersion) {
|
public Modpack setGameVersion(String gameVersion) {
|
||||||
return new Modpack(name, author, version, gameVersion, description, manifest);
|
return new Modpack(name, author, version, gameVersion, description, encoding, manifest);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDescription() {
|
public String getDescription() {
|
||||||
return description;
|
return description;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Charset getEncoding() {
|
||||||
|
return encoding;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Modpack setEncoding(Charset encoding) {
|
||||||
|
return new Modpack(name, author, version, gameVersion, description, encoding, manifest);
|
||||||
|
}
|
||||||
|
|
||||||
public Object getManifest() {
|
public Object getManifest() {
|
||||||
return manifest;
|
return manifest;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Modpack setManifest(Object manifest) {
|
public Modpack setManifest(Object manifest) {
|
||||||
return new Modpack(name, author, version, gameVersion, description, manifest);
|
return new Modpack(name, author, version, gameVersion, description, encoding, manifest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import org.jackhuang.hmcl.util.io.Unzipper;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
@@ -34,13 +35,15 @@ public class ModpackInstallTask<T> extends Task {
|
|||||||
|
|
||||||
private final File modpackFile;
|
private final File modpackFile;
|
||||||
private final File dest;
|
private final File dest;
|
||||||
|
private final Charset charset;
|
||||||
private final String subDirectory;
|
private final String subDirectory;
|
||||||
private final List<ModpackConfiguration.FileInformation> overrides;
|
private final List<ModpackConfiguration.FileInformation> overrides;
|
||||||
private final Predicate<String> callback;
|
private final Predicate<String> callback;
|
||||||
|
|
||||||
public ModpackInstallTask(File modpackFile, File dest, String subDirectory, Predicate<String> callback, ModpackConfiguration<T> oldConfiguration) {
|
public ModpackInstallTask(File modpackFile, File dest, Charset charset, String subDirectory, Predicate<String> callback, ModpackConfiguration<T> oldConfiguration) {
|
||||||
this.modpackFile = modpackFile;
|
this.modpackFile = modpackFile;
|
||||||
this.dest = dest;
|
this.dest = dest;
|
||||||
|
this.charset = charset;
|
||||||
this.subDirectory = subDirectory;
|
this.subDirectory = subDirectory;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
|
|
||||||
@@ -64,6 +67,7 @@ public class ModpackInstallTask<T> extends Task {
|
|||||||
.setSubDirectory(subDirectory)
|
.setSubDirectory(subDirectory)
|
||||||
.setTerminateIfSubDirectoryNotExists()
|
.setTerminateIfSubDirectoryNotExists()
|
||||||
.setReplaceExistentFile(true)
|
.setReplaceExistentFile(true)
|
||||||
|
.setEncoding(charset)
|
||||||
.setFilter((destPath, isDirectory, zipEntry, entryPath) -> {
|
.setFilter((destPath, isDirectory, zipEntry, entryPath) -> {
|
||||||
if (isDirectory) return true;
|
if (isDirectory) return true;
|
||||||
if (!callback.test(entryPath)) return false;
|
if (!callback.test(entryPath)) return false;
|
||||||
|
|||||||
@@ -21,9 +21,9 @@ import org.jackhuang.hmcl.util.Lang;
|
|||||||
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 java.io.File;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
import java.nio.file.FileSystem;
|
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;
|
||||||
@@ -264,9 +264,9 @@ public final class MultiMCInstanceConfiguration {
|
|||||||
return mmcPack;
|
return mmcPack;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Modpack readMultiMCModpackManifest(File modpackFile) throws IOException {
|
public static Modpack readMultiMCModpackManifest(Path modpackFile, Charset encoding) throws IOException {
|
||||||
MultiMCManifest manifest = MultiMCManifest.readMultiMCModpackManifest(modpackFile);
|
MultiMCManifest manifest = MultiMCManifest.readMultiMCModpackManifest(modpackFile, encoding);
|
||||||
try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(modpackFile.toPath())) {
|
try (FileSystem fs = CompressingUtils.readonly(modpackFile).setEncoding(encoding).build()) {
|
||||||
Path root = Files.list(fs.getPath("/")).filter(Files::isDirectory).findAny()
|
Path root = Files.list(fs.getPath("/")).filter(Files::isDirectory).findAny()
|
||||||
.orElseThrow(() -> new IOException("Not a valid MultiMC modpack"));
|
.orElseThrow(() -> new IOException("Not a valid MultiMC modpack"));
|
||||||
String name = StringUtils.removeSuffix(root.normalize().getFileName().toString(), "/");
|
String name = StringUtils.removeSuffix(root.normalize().getFileName().toString(), "/");
|
||||||
@@ -275,7 +275,7 @@ public final class MultiMCInstanceConfiguration {
|
|||||||
if (Files.notExists(instancePath))
|
if (Files.notExists(instancePath))
|
||||||
throw new IOException("`instance.cfg` not found, " + modpackFile + " is not a valid MultiMC modpack.");
|
throw new IOException("`instance.cfg` not found, " + modpackFile + " is not a valid MultiMC modpack.");
|
||||||
MultiMCInstanceConfiguration cfg = new MultiMCInstanceConfiguration(name, Files.newInputStream(instancePath), manifest);
|
MultiMCInstanceConfiguration cfg = new MultiMCInstanceConfiguration(name, Files.newInputStream(instancePath), manifest);
|
||||||
return new Modpack(cfg.getName(), "", "", cfg.getGameVersion(), cfg.getNotes(), cfg);
|
return new Modpack(cfg.getName(), "", "", cfg.getGameVersion(), cfg.getNotes(), encoding, cfg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,14 +18,13 @@
|
|||||||
package org.jackhuang.hmcl.mod;
|
package org.jackhuang.hmcl.mod;
|
||||||
|
|
||||||
import com.google.gson.annotations.SerializedName;
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
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.io.CompressingUtils;
|
import org.jackhuang.hmcl.util.io.CompressingUtils;
|
||||||
import org.jackhuang.hmcl.util.io.IOUtils;
|
import org.jackhuang.hmcl.util.io.IOUtils;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
import java.nio.file.FileSystem;
|
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;
|
||||||
@@ -53,8 +52,8 @@ public final class MultiMCManifest {
|
|||||||
return components;
|
return components;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MultiMCManifest readMultiMCModpackManifest(File zipFile) throws IOException {
|
public static MultiMCManifest readMultiMCModpackManifest(Path zipFile, Charset encoding) throws IOException {
|
||||||
try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(zipFile.toPath())) {
|
try (FileSystem fs = CompressingUtils.readonly(zipFile).setEncoding(encoding).build()) {
|
||||||
Path root = Files.list(fs.getPath("/")).filter(Files::isDirectory).findAny()
|
Path root = Files.list(fs.getPath("/")).filter(Files::isDirectory).findAny()
|
||||||
.orElseThrow(() -> new IOException("Not a valid MultiMC modpack"));
|
.orElseThrow(() -> new IOException("Not a valid MultiMC modpack"));
|
||||||
Path mmcPack = root.resolve("mmc-pack.json");
|
Path mmcPack = root.resolve("mmc-pack.json");
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import org.jackhuang.hmcl.game.Arguments;
|
|||||||
import org.jackhuang.hmcl.game.DefaultGameRepository;
|
import org.jackhuang.hmcl.game.DefaultGameRepository;
|
||||||
import org.jackhuang.hmcl.game.Version;
|
import org.jackhuang.hmcl.game.Version;
|
||||||
import org.jackhuang.hmcl.task.Task;
|
import org.jackhuang.hmcl.task.Task;
|
||||||
import org.jackhuang.hmcl.util.*;
|
import org.jackhuang.hmcl.util.Lang;
|
||||||
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;
|
||||||
@@ -49,14 +49,16 @@ import java.util.Optional;
|
|||||||
public final class MultiMCModpackInstallTask extends Task {
|
public final class MultiMCModpackInstallTask extends Task {
|
||||||
|
|
||||||
private final File zipFile;
|
private final File zipFile;
|
||||||
|
private final Modpack modpack;
|
||||||
private final MultiMCInstanceConfiguration manifest;
|
private final MultiMCInstanceConfiguration manifest;
|
||||||
private final String name;
|
private final String name;
|
||||||
private final DefaultGameRepository repository;
|
private final DefaultGameRepository repository;
|
||||||
private final List<Task> dependencies = new LinkedList<>();
|
private final List<Task> dependencies = new LinkedList<>();
|
||||||
private final List<Task> dependents = new LinkedList<>();
|
private final List<Task> dependents = new LinkedList<>();
|
||||||
|
|
||||||
public MultiMCModpackInstallTask(DefaultDependencyManager dependencyManager, File zipFile, MultiMCInstanceConfiguration manifest, String name) {
|
public MultiMCModpackInstallTask(DefaultDependencyManager dependencyManager, File zipFile, Modpack modpack, MultiMCInstanceConfiguration manifest, String name) {
|
||||||
this.zipFile = zipFile;
|
this.zipFile = zipFile;
|
||||||
|
this.modpack = modpack;
|
||||||
this.manifest = manifest;
|
this.manifest = manifest;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.repository = dependencyManager.getGameRepository();
|
this.repository = dependencyManager.getGameRepository();
|
||||||
@@ -100,7 +102,7 @@ public final class MultiMCModpackInstallTask extends Task {
|
|||||||
} catch (JsonParseException | IOException ignore) {
|
} catch (JsonParseException | IOException ignore) {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependents.add(new ModpackInstallTask<>(zipFile, run, "/" + manifest.getName() + "/minecraft", any -> true, config));
|
dependents.add(new ModpackInstallTask<>(zipFile, run, modpack.getEncoding(), "/" + manifest.getName() + "/minecraft", any -> true, config));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -141,7 +143,7 @@ public final class MultiMCModpackInstallTask extends Task {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies.add(new VersionJsonSaveTask(repository, version));
|
dependencies.add(new VersionJsonSaveTask(repository, version));
|
||||||
dependencies.add(new MinecraftInstanceTask<>(zipFile, "/" + manifest.getName() + "/minecraft", manifest, MODPACK_TYPE, repository.getModpackConfiguration(name)));
|
dependencies.add(new MinecraftInstanceTask<>(zipFile, modpack.getEncoding(), "/" + manifest.getName() + "/minecraft", manifest, MODPACK_TYPE, repository.getModpackConfiguration(name)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final String MODPACK_TYPE = "MultiMC";
|
public static final String MODPACK_TYPE = "MultiMC";
|
||||||
|
|||||||
@@ -23,7 +23,10 @@ import javafx.beans.property.ReadOnlyDoubleWrapper;
|
|||||||
import javafx.beans.property.ReadOnlyStringProperty;
|
import javafx.beans.property.ReadOnlyStringProperty;
|
||||||
import javafx.beans.property.ReadOnlyStringWrapper;
|
import javafx.beans.property.ReadOnlyStringWrapper;
|
||||||
import org.jackhuang.hmcl.event.EventManager;
|
import org.jackhuang.hmcl.event.EventManager;
|
||||||
import org.jackhuang.hmcl.util.*;
|
import org.jackhuang.hmcl.util.AutoTypingMap;
|
||||||
|
import org.jackhuang.hmcl.util.InvocationDispatcher;
|
||||||
|
import org.jackhuang.hmcl.util.Logging;
|
||||||
|
import org.jackhuang.hmcl.util.ReflectionHelper;
|
||||||
import org.jackhuang.hmcl.util.function.ExceptionalConsumer;
|
import org.jackhuang.hmcl.util.function.ExceptionalConsumer;
|
||||||
import org.jackhuang.hmcl.util.function.ExceptionalFunction;
|
import org.jackhuang.hmcl.util.function.ExceptionalFunction;
|
||||||
import org.jackhuang.hmcl.util.function.ExceptionalRunnable;
|
import org.jackhuang.hmcl.util.function.ExceptionalRunnable;
|
||||||
@@ -31,7 +34,6 @@ import org.jackhuang.hmcl.util.function.ExceptionalRunnable;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -363,7 +365,7 @@ public abstract class Task {
|
|||||||
return new TaskCallable<>(id, callable);
|
return new TaskCallable<>(id, callable);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <V> TaskResult<V> ofResult(String id, Function<AutoTypingMap<String>, V> closure) {
|
public static <V> TaskResult<V> ofResult(String id, ExceptionalFunction<AutoTypingMap<String>, V, ?> closure) {
|
||||||
return new TaskCallable2<>(id, closure);
|
return new TaskCallable2<>(id, closure);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,8 +18,7 @@
|
|||||||
package org.jackhuang.hmcl.task;
|
package org.jackhuang.hmcl.task;
|
||||||
|
|
||||||
import org.jackhuang.hmcl.util.AutoTypingMap;
|
import org.jackhuang.hmcl.util.AutoTypingMap;
|
||||||
|
import org.jackhuang.hmcl.util.function.ExceptionalFunction;
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -28,9 +27,9 @@ import java.util.function.Function;
|
|||||||
class TaskCallable2<V> extends TaskResult<V> {
|
class TaskCallable2<V> extends TaskResult<V> {
|
||||||
|
|
||||||
private final String id;
|
private final String id;
|
||||||
private final Function<AutoTypingMap<String>, V> callable;
|
private final ExceptionalFunction<AutoTypingMap<String>, V, ?> callable;
|
||||||
|
|
||||||
public TaskCallable2(String id, Function<AutoTypingMap<String>, V> callable) {
|
public TaskCallable2(String id, ExceptionalFunction<AutoTypingMap<String>, V, ?> callable) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.callable = callable;
|
this.callable = callable;
|
||||||
}
|
}
|
||||||
@@ -41,7 +40,7 @@ class TaskCallable2<V> extends TaskResult<V> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute() {
|
public void execute() throws Exception {
|
||||||
setResult(callable.apply(getVariables()));
|
setResult(callable.apply(getVariables()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,14 +17,20 @@
|
|||||||
*/
|
*/
|
||||||
package org.jackhuang.hmcl.util.io;
|
package org.jackhuang.hmcl.util.io;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.FileSystem;
|
import java.nio.charset.Charset;
|
||||||
import java.nio.file.Path;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.*;
|
||||||
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
import java.nio.file.spi.FileSystemProvider;
|
import java.nio.file.spi.FileSystemProvider;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.zip.ZipError;
|
import java.util.zip.ZipError;
|
||||||
import java.util.zip.ZipException;
|
import java.util.zip.ZipException;
|
||||||
|
|
||||||
@@ -43,28 +49,127 @@ public final class CompressingUtils {
|
|||||||
private CompressingUtils() {
|
private CompressingUtils() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private static FileVisitResult testZipPath(Path file, Path root, AtomicBoolean result) {
|
||||||
|
try {
|
||||||
|
root.relativize(file).toString(); // throw IllegalArgumentException for wrong encoding.
|
||||||
|
return FileVisitResult.CONTINUE;
|
||||||
|
} catch (Exception e) {
|
||||||
|
result.set(false);
|
||||||
|
return FileVisitResult.TERMINATE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean testEncoding(Path zipFile, Charset encoding) throws IOException {
|
||||||
|
AtomicBoolean result = new AtomicBoolean(true);
|
||||||
|
try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(zipFile, encoding)) {
|
||||||
|
Path root = fs.getPath("/");
|
||||||
|
Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
|
||||||
|
@Override
|
||||||
|
public FileVisitResult visitFile(Path file,
|
||||||
|
BasicFileAttributes attrs) {
|
||||||
|
return testZipPath(file, root, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileVisitResult preVisitDirectory(Path dir,
|
||||||
|
BasicFileAttributes attrs) {
|
||||||
|
return testZipPath(dir, root, result);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return result.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Charset findSuitableEncoding(Path zipFile) throws IOException {
|
||||||
|
return findSuitableEncoding(zipFile, Charset.availableCharsets().values());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Charset findSuitableEncoding(Path zipFile, Collection<Charset> candidates) throws IOException {
|
||||||
|
if (testEncoding(zipFile, StandardCharsets.UTF_8)) return StandardCharsets.UTF_8;
|
||||||
|
if (testEncoding(zipFile, Charset.defaultCharset())) return Charset.defaultCharset();
|
||||||
|
|
||||||
|
for (Charset charset : candidates)
|
||||||
|
if (charset != null && testEncoding(zipFile, charset))
|
||||||
|
return charset;
|
||||||
|
throw new IOException("Cannot find suitable encoding for the zip.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class Builder {
|
||||||
|
private boolean autoDetectEncoding = false;
|
||||||
|
private Collection<Charset> charsetCandidates;
|
||||||
|
private Charset encoding = StandardCharsets.UTF_8;
|
||||||
|
private boolean useTempFile = false;
|
||||||
|
private final boolean create;
|
||||||
|
private final Path zip;
|
||||||
|
|
||||||
|
public Builder(Path zip, boolean create) {
|
||||||
|
this.zip = zip;
|
||||||
|
this.create = create;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setAutoDetectEncoding(boolean autoDetectEncoding) {
|
||||||
|
this.autoDetectEncoding = autoDetectEncoding;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setCharsetCandidates(Collection<Charset> charsetCandidates) {
|
||||||
|
this.charsetCandidates = charsetCandidates;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setEncoding(Charset encoding) {
|
||||||
|
this.encoding = encoding;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setUseTempFile(boolean useTempFile) {
|
||||||
|
this.useTempFile = useTempFile;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FileSystem build() throws IOException {
|
||||||
|
if (autoDetectEncoding) {
|
||||||
|
if (!testEncoding(zip, encoding)) {
|
||||||
|
if (charsetCandidates == null)
|
||||||
|
charsetCandidates = Charset.availableCharsets().values();
|
||||||
|
encoding = findSuitableEncoding(zip, charsetCandidates);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return createZipFileSystem(zip, create, useTempFile, encoding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Builder readonly(Path zipFile) {
|
||||||
|
return new Builder(zipFile, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Builder writable(Path zipFile) {
|
||||||
|
return new Builder(zipFile, true).setUseTempFile(true);
|
||||||
|
}
|
||||||
|
|
||||||
public static FileSystem createReadOnlyZipFileSystem(Path zipFile) throws IOException {
|
public static FileSystem createReadOnlyZipFileSystem(Path zipFile) throws IOException {
|
||||||
return createReadOnlyZipFileSystem(zipFile, null);
|
return createReadOnlyZipFileSystem(zipFile, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FileSystem createReadOnlyZipFileSystem(Path zipFile, String encoding) throws IOException {
|
public static FileSystem createReadOnlyZipFileSystem(Path zipFile, Charset charset) throws IOException {
|
||||||
return createZipFileSystem(zipFile, false, false, encoding);
|
return createZipFileSystem(zipFile, false, false, charset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FileSystem createWritableZipFileSystem(Path zipFile) throws IOException {
|
public static FileSystem createWritableZipFileSystem(Path zipFile) throws IOException {
|
||||||
return createWritableZipFileSystem(zipFile, null);
|
return createWritableZipFileSystem(zipFile, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FileSystem createWritableZipFileSystem(Path zipFile, String encoding) throws IOException {
|
public static FileSystem createWritableZipFileSystem(Path zipFile, Charset charset) throws IOException {
|
||||||
return createZipFileSystem(zipFile, true, true, encoding);
|
return createZipFileSystem(zipFile, true, true, charset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FileSystem createZipFileSystem(Path zipFile, boolean create, boolean useTempFile, String encoding) throws IOException {
|
public static FileSystem createZipFileSystem(Path zipFile, boolean create, boolean useTempFile, Charset encoding) throws IOException {
|
||||||
Map<String, Object> env = new HashMap<>();
|
Map<String, Object> env = new HashMap<>();
|
||||||
if (create)
|
if (create)
|
||||||
env.put("create", "true");
|
env.put("create", "true");
|
||||||
if (encoding != null)
|
if (encoding != null)
|
||||||
env.put("encoding", encoding);
|
env.put("encoding", encoding.name());
|
||||||
if (useTempFile)
|
if (useTempFile)
|
||||||
env.put("useTempFile", true);
|
env.put("useTempFile", true);
|
||||||
try {
|
try {
|
||||||
@@ -86,7 +191,19 @@ public final class CompressingUtils {
|
|||||||
* @return the plain text content of given file.
|
* @return the plain text content of given file.
|
||||||
*/
|
*/
|
||||||
public static String readTextZipEntry(File zipFile, String name) throws IOException {
|
public static String readTextZipEntry(File zipFile, String name) throws IOException {
|
||||||
try (FileSystem fs = createReadOnlyZipFileSystem(zipFile.toPath())) {
|
return readTextZipEntry(zipFile.toPath(), name, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read the text content of a file in zip.
|
||||||
|
*
|
||||||
|
* @param zipFile the zip file
|
||||||
|
* @param name the location of the text in zip file, something like A/B/C/D.txt
|
||||||
|
* @throws IOException if the file is not a valid zip file.
|
||||||
|
* @return the plain text content of given file.
|
||||||
|
*/
|
||||||
|
public static String readTextZipEntry(Path zipFile, String name, Charset encoding) throws IOException {
|
||||||
|
try (FileSystem fs = createReadOnlyZipFileSystem(zipFile, encoding)) {
|
||||||
return FileUtils.readText(fs.getPath(name));
|
return FileUtils.readText(fs.getPath(name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -105,4 +222,19 @@ public final class CompressingUtils {
|
|||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read the text content of a file in zip.
|
||||||
|
*
|
||||||
|
* @param file the zip file
|
||||||
|
* @param name the location of the text in zip file, something like A/B/C/D.txt
|
||||||
|
* @return the plain text content of given file.
|
||||||
|
*/
|
||||||
|
public static Optional<String> readTextZipEntryQuietly(Path file, String name, Charset encoding) {
|
||||||
|
try {
|
||||||
|
return Optional.of(readTextZipEntry(file, name, encoding));
|
||||||
|
} catch (IOException e) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ package org.jackhuang.hmcl.util.io;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.*;
|
import java.nio.file.*;
|
||||||
import java.nio.file.attribute.BasicFileAttributes;
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
|
|
||||||
@@ -28,7 +30,7 @@ public class Unzipper {
|
|||||||
private boolean terminateIfSubDirectoryNotExists = false;
|
private boolean terminateIfSubDirectoryNotExists = false;
|
||||||
private String subDirectory = "/";
|
private String subDirectory = "/";
|
||||||
private FileFilter filter = null;
|
private FileFilter filter = null;
|
||||||
private String encoding;
|
private Charset encoding = StandardCharsets.UTF_8;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decompress the given zip file to a directory.
|
* Decompress the given zip file to a directory.
|
||||||
@@ -82,7 +84,7 @@ public class Unzipper {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Unzipper setEncoding(String encoding) {
|
public Unzipper setEncoding(Charset encoding) {
|
||||||
this.encoding = encoding;
|
this.encoding = encoding;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -99,7 +101,7 @@ public class Unzipper {
|
|||||||
*/
|
*/
|
||||||
public void unzip() throws IOException {
|
public void unzip() throws IOException {
|
||||||
Files.createDirectories(dest);
|
Files.createDirectories(dest);
|
||||||
try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(zipFile, encoding)) {
|
try (FileSystem fs = CompressingUtils.readonly(zipFile).setEncoding(encoding).setAutoDetectEncoding(true).build()) {
|
||||||
Path root = fs.getPath(subDirectory);
|
Path root = fs.getPath(subDirectory);
|
||||||
if (!root.isAbsolute() || (subDirectory.length() > 1 && subDirectory.endsWith("/")))
|
if (!root.isAbsolute() || (subDirectory.length() > 1 && subDirectory.endsWith("/")))
|
||||||
throw new IllegalArgumentException("Subdirectory for unzipper must be absolute");
|
throw new IllegalArgumentException("Subdirectory for unzipper must be absolute");
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import java.io.Closeable;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
import java.nio.file.*;
|
import java.nio.file.*;
|
||||||
import java.nio.file.attribute.BasicFileAttributes;
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
@@ -39,7 +40,7 @@ public final class Zipper implements Closeable {
|
|||||||
this(zipFile, null);
|
this(zipFile, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Zipper(Path zipFile, String encoding) throws IOException {
|
public Zipper(Path zipFile, Charset encoding) throws IOException {
|
||||||
Files.deleteIfExists(zipFile);
|
Files.deleteIfExists(zipFile);
|
||||||
fs = CompressingUtils.createWritableZipFileSystem(zipFile, encoding);
|
fs = CompressingUtils.createWritableZipFileSystem(zipFile, encoding);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user