fix compressingutils
This commit is contained in:
parent
92b1df630e
commit
60ab40cc57
|
@ -27,6 +27,7 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.github.marschall:zipfilesystem-standalone:1.0.1'
|
||||
implementation 'org.nanohttpd:nanohttpd:2.3.1'
|
||||
implementation 'com.github.steveice10:opennbt:1.4'
|
||||
implementation 'org.apache.commons:commons-lang3:3.12.0'
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
package com.tungsten.fclcore.constant;
|
||||
|
||||
public class RequestCodes {
|
||||
}
|
|
@ -13,6 +13,7 @@ import com.tungsten.fclcore.game.Version;
|
|||
import com.tungsten.fclcore.task.FileDownloadTask;
|
||||
import com.tungsten.fclcore.task.Task;
|
||||
import com.tungsten.fclcore.util.gson.JsonUtils;
|
||||
import com.tungsten.fclcore.util.io.CompressingUtils;
|
||||
import com.tungsten.fclcore.util.io.FileUtils;
|
||||
import com.tungsten.fclcore.util.versioning.VersionNumber;
|
||||
|
||||
|
@ -25,7 +26,6 @@ import java.util.Collections;
|
|||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
// Todo : fix
|
||||
public final class ForgeInstallTask extends Task<Version> {
|
||||
|
||||
private final DefaultDependencyManager dependencyManager;
|
||||
|
|
|
@ -4,6 +4,7 @@ import com.tungsten.fclcore.download.DefaultDependencyManager;
|
|||
import com.tungsten.fclcore.download.LibraryAnalyzer;
|
||||
import com.tungsten.fclcore.game.Version;
|
||||
import com.tungsten.fclcore.task.Task;
|
||||
import com.tungsten.fclcore.util.io.CompressingUtils;
|
||||
import com.tungsten.fclcore.util.versioning.VersionNumber;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -18,7 +19,6 @@ import java.util.List;
|
|||
/**
|
||||
* Remove class digital verification file in game jar
|
||||
*/
|
||||
// Todo : fix
|
||||
public final class GameVerificationFixTask extends Task<Void> {
|
||||
private final DefaultDependencyManager dependencyManager;
|
||||
private final String gameVersion;
|
||||
|
|
|
@ -15,6 +15,7 @@ import com.tungsten.fclcore.game.LibraryDownloadInfo;
|
|||
import com.tungsten.fclcore.game.Version;
|
||||
import com.tungsten.fclcore.task.FileDownloadTask;
|
||||
import com.tungsten.fclcore.task.Task;
|
||||
import com.tungsten.fclcore.util.io.CompressingUtils;
|
||||
import com.tungsten.fclcore.util.io.FileUtils;
|
||||
import com.tungsten.fclcore.util.platform.CommandBuilder;
|
||||
import com.tungsten.fclcore.util.versioning.VersionNumber;
|
||||
|
|
|
@ -5,6 +5,7 @@ import static com.tungsten.fclcore.util.Logging.LOG;
|
|||
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.tungsten.fclcore.util.gson.JsonUtils;
|
||||
import com.tungsten.fclcore.util.io.CompressingUtils;
|
||||
import com.tungsten.fclcore.util.io.FileUtils;
|
||||
|
||||
import org.jenkinsci.constant_pool_scanner.ConstantPool;
|
||||
|
@ -24,7 +25,6 @@ import java.util.logging.Level;
|
|||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
// Todo : fix
|
||||
public final class GameVersion {
|
||||
private GameVersion() {
|
||||
}
|
||||
|
|
|
@ -1,6 +1,15 @@
|
|||
package com.tungsten.fclcore.game;
|
||||
|
||||
import com.github.steveice10.opennbt.NBTIO;
|
||||
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.LongTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.StringTag;
|
||||
import com.github.steveice10.opennbt.tag.builtin.Tag;
|
||||
import com.tungsten.fclcore.util.Logging;
|
||||
import com.tungsten.fclcore.util.io.CompressingUtils;
|
||||
import com.tungsten.fclcore.util.io.FileUtils;
|
||||
import com.tungsten.fclcore.util.io.Unzipper;
|
||||
import com.tungsten.fclcore.util.io.Zipper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
@ -13,7 +22,6 @@ import java.util.stream.Stream;
|
|||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
// Todo : fix
|
||||
public class World {
|
||||
|
||||
private final Path file;
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.tungsten.fclcore.mod;
|
|||
import com.google.gson.JsonParseException;
|
||||
import com.tungsten.fclcore.util.Logging;
|
||||
import com.tungsten.fclcore.util.gson.JsonUtils;
|
||||
import com.tungsten.fclcore.util.io.CompressingUtils;
|
||||
import com.tungsten.fclcore.util.io.FileUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.tungsten.fclcore.mod;
|
|||
import com.google.gson.*;
|
||||
import com.google.gson.annotations.JsonAdapter;
|
||||
import com.tungsten.fclcore.util.gson.JsonUtils;
|
||||
import com.tungsten.fclcore.util.io.CompressingUtils;
|
||||
import com.tungsten.fclcore.util.io.FileUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -15,7 +16,6 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
// Todo : fix
|
||||
public final class FabricModMetadata {
|
||||
private final String id;
|
||||
private final String name;
|
||||
|
|
|
@ -4,6 +4,7 @@ import static com.tungsten.fclcore.util.Logging.LOG;
|
|||
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.moandjiezana.toml.Toml;
|
||||
import com.tungsten.fclcore.util.io.CompressingUtils;
|
||||
import com.tungsten.fclcore.util.io.FileUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -16,7 +17,6 @@ import java.util.jar.Attributes;
|
|||
import java.util.jar.Manifest;
|
||||
import java.util.logging.Level;
|
||||
|
||||
// Todo : fix
|
||||
public final class ForgeNewModMetadata {
|
||||
|
||||
private final String modLoader;
|
||||
|
|
|
@ -5,6 +5,7 @@ import com.google.gson.annotations.SerializedName;
|
|||
import com.google.gson.reflect.TypeToken;
|
||||
import com.tungsten.fclcore.util.StringUtils;
|
||||
import com.tungsten.fclcore.util.gson.JsonUtils;
|
||||
import com.tungsten.fclcore.util.io.CompressingUtils;
|
||||
import com.tungsten.fclcore.util.io.FileUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -13,7 +14,6 @@ import java.nio.file.Files;
|
|||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
// Todo : fix
|
||||
public final class ForgeOldModMetadata {
|
||||
|
||||
@SerializedName("modid")
|
||||
|
|
|
@ -5,6 +5,7 @@ import static com.tungsten.fclcore.util.Hex.encodeHex;
|
|||
|
||||
import com.tungsten.fclcore.task.Task;
|
||||
import com.tungsten.fclcore.util.gson.JsonUtils;
|
||||
import com.tungsten.fclcore.util.io.CompressingUtils;
|
||||
import com.tungsten.fclcore.util.io.FileUtils;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -16,7 +17,6 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
// Todo : fix
|
||||
public final class MinecraftInstanceTask<T> extends Task<ModpackConfiguration<T>> {
|
||||
|
||||
private final File zipFile;
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.tungsten.fclcore.mod;
|
|||
|
||||
import com.tungsten.fclcore.game.GameRepository;
|
||||
import com.tungsten.fclcore.util.StringUtils;
|
||||
import com.tungsten.fclcore.util.io.CompressingUtils;
|
||||
import com.tungsten.fclcore.util.io.FileUtils;
|
||||
import com.tungsten.fclcore.util.versioning.VersionNumber;
|
||||
|
||||
|
@ -12,7 +13,6 @@ import java.util.HashMap;
|
|||
import java.util.Objects;
|
||||
import java.util.TreeSet;
|
||||
|
||||
// Todo : fix
|
||||
public final class ModManager {
|
||||
private final GameRepository repository;
|
||||
private final String id;
|
||||
|
|
|
@ -5,6 +5,7 @@ import static com.tungsten.fclcore.util.Hex.encodeHex;
|
|||
|
||||
import com.tungsten.fclcore.task.Task;
|
||||
import com.tungsten.fclcore.util.io.FileUtils;
|
||||
import com.tungsten.fclcore.util.io.Unzipper;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
@ -13,7 +14,6 @@ import java.nio.file.Files;
|
|||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
// Todo : fix
|
||||
public class ModpackInstallTask<T> extends Task<Void> {
|
||||
|
||||
private final File modpackFile;
|
||||
|
|
|
@ -5,6 +5,7 @@ import com.google.gson.annotations.JsonAdapter;
|
|||
import com.google.gson.annotations.SerializedName;
|
||||
import com.tungsten.fclcore.util.gson.JsonUtils;
|
||||
import com.tungsten.fclcore.util.gson.Validation;
|
||||
import com.tungsten.fclcore.util.io.CompressingUtils;
|
||||
import com.tungsten.fclcore.util.io.FileUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -16,7 +17,6 @@ import java.util.ArrayList;
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
// Todo : fix
|
||||
public class PackMcMeta implements Validation {
|
||||
|
||||
@SerializedName("pack")
|
||||
|
|
|
@ -8,6 +8,7 @@ import com.tungsten.fclcore.mod.ModpackProvider;
|
|||
import com.tungsten.fclcore.mod.ModpackUpdateTask;
|
||||
import com.tungsten.fclcore.task.Task;
|
||||
import com.tungsten.fclcore.util.gson.JsonUtils;
|
||||
import com.tungsten.fclcore.util.io.CompressingUtils;
|
||||
import com.tungsten.fclcore.util.io.IOUtils;
|
||||
|
||||
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
|
||||
|
@ -18,7 +19,6 @@ import java.io.IOException;
|
|||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Path;
|
||||
|
||||
// Todo : fix
|
||||
public final class CurseModpackProvider implements ModpackProvider {
|
||||
public static final CurseModpackProvider INSTANCE = new CurseModpackProvider();
|
||||
|
||||
|
|
|
@ -15,10 +15,13 @@ import com.tungsten.fclcore.mod.ModAdviser;
|
|||
import com.tungsten.fclcore.mod.Modpack;
|
||||
import com.tungsten.fclcore.mod.ModpackExportInfo;
|
||||
import com.tungsten.fclcore.mod.curse.CurseManifest;
|
||||
import com.tungsten.fclcore.mod.curse.CurseManifestMinecraft;
|
||||
import com.tungsten.fclcore.mod.curse.CurseManifestModLoader;
|
||||
import com.tungsten.fclcore.task.Task;
|
||||
import com.tungsten.fclcore.util.Logging;
|
||||
import com.tungsten.fclcore.util.StringUtils;
|
||||
import com.tungsten.fclcore.util.gson.JsonUtils;
|
||||
import com.tungsten.fclcore.util.io.Zipper;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
@ -28,7 +31,6 @@ import java.util.ArrayList;
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
// Todo : fix
|
||||
public class McbbsModpackExportTask extends Task<Void> {
|
||||
private final DefaultGameRepository repository;
|
||||
private final String version;
|
||||
|
|
|
@ -99,7 +99,6 @@ public class McbbsModpackLocalInstallTask extends Task<Void> {
|
|||
dependencies.add(repository.saveAsync(version.addPatch(patch)));
|
||||
} else {
|
||||
// This mcbbs modpack was installed by other launchers.
|
||||
// TODO: maintain libraries.
|
||||
}
|
||||
|
||||
dependencies.add(new McbbsModpackCompletionTask(dependencyManager, name, instanceTask.getResult()));
|
||||
|
|
|
@ -8,6 +8,7 @@ import com.tungsten.fclcore.mod.ModpackProvider;
|
|||
import com.tungsten.fclcore.mod.ModpackUpdateTask;
|
||||
import com.tungsten.fclcore.task.Task;
|
||||
import com.tungsten.fclcore.util.gson.JsonUtils;
|
||||
import com.tungsten.fclcore.util.io.CompressingUtils;
|
||||
|
||||
import org.apache.commons.compress.archivers.zip.ZipFile;
|
||||
|
||||
|
@ -16,7 +17,6 @@ import java.io.IOException;
|
|||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Path;
|
||||
|
||||
// Todo : fix
|
||||
public final class ModrinthModpackProvider implements ModpackProvider {
|
||||
public static final ModrinthModpackProvider INSTANCE = new ModrinthModpackProvider();
|
||||
|
||||
|
|
|
@ -7,10 +7,12 @@ import static com.tungsten.fclcore.download.LibraryAnalyzer.LibraryType.LITELOAD
|
|||
import com.tungsten.fclcore.download.LibraryAnalyzer;
|
||||
import com.tungsten.fclcore.game.DefaultGameRepository;
|
||||
import com.tungsten.fclcore.mod.ModAdviser;
|
||||
import com.tungsten.fclcore.mod.Modpack;
|
||||
import com.tungsten.fclcore.mod.ModpackExportInfo;
|
||||
import com.tungsten.fclcore.task.Task;
|
||||
import com.tungsten.fclcore.util.Logging;
|
||||
import com.tungsten.fclcore.util.gson.JsonUtils;
|
||||
import com.tungsten.fclcore.util.io.Zipper;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
@ -21,7 +23,6 @@ import java.util.List;
|
|||
/**
|
||||
* Export the game to a mod pack file.
|
||||
*/
|
||||
// Todo : fix
|
||||
public class MultiMCModpackExportTask extends Task<Void> {
|
||||
private final DefaultGameRepository repository;
|
||||
private final String versionId;
|
||||
|
|
|
@ -13,6 +13,7 @@ import com.tungsten.fclcore.mod.ModpackConfiguration;
|
|||
import com.tungsten.fclcore.mod.ModpackInstallTask;
|
||||
import com.tungsten.fclcore.task.Task;
|
||||
import com.tungsten.fclcore.util.gson.JsonUtils;
|
||||
import com.tungsten.fclcore.util.io.CompressingUtils;
|
||||
import com.tungsten.fclcore.util.io.FileUtils;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -26,7 +27,6 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
// Todo : fix
|
||||
public final class MultiMCModpackInstallTask extends Task<Void> {
|
||||
|
||||
private final File zipFile;
|
||||
|
|
|
@ -19,12 +19,12 @@ import static java.util.Objects.requireNonNull;
|
|||
|
||||
import com.tungsten.fclcore.util.Logging;
|
||||
import com.tungsten.fclcore.util.io.ChecksumMismatchException;
|
||||
import com.tungsten.fclcore.util.io.CompressingUtils;
|
||||
import com.tungsten.fclcore.util.io.FileUtils;
|
||||
|
||||
/**
|
||||
* A task that can download a file online.
|
||||
*/
|
||||
// Todo : fix
|
||||
public class FileDownloadTask extends FetchTask<Void> {
|
||||
|
||||
public static class IntegrityCheck {
|
||||
|
|
|
@ -0,0 +1,260 @@
|
|||
package com.tungsten.fclcore.util.io;
|
||||
|
||||
import com.github.marschall.com.sun.nio.zipfs.ZipFileSystemProvider;
|
||||
import com.tungsten.fclcore.util.platform.OperatingSystem;
|
||||
|
||||
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
|
||||
import org.apache.commons.compress.archivers.zip.ZipFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.Buffer;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.*;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.spi.FileSystemProvider;
|
||||
import java.util.*;
|
||||
import java.util.zip.ZipError;
|
||||
import java.util.zip.ZipException;
|
||||
|
||||
/**
|
||||
* Utilities of compressing
|
||||
*/
|
||||
public final class CompressingUtils {
|
||||
|
||||
private static final FileSystemProvider ZIPFS_PROVIDER = new ZipFileSystemProvider();
|
||||
|
||||
private CompressingUtils() {
|
||||
}
|
||||
|
||||
private static CharsetDecoder newCharsetDecoder(Charset charset) {
|
||||
return charset.newDecoder().onMalformedInput(CodingErrorAction.REPORT).onUnmappableCharacter(CodingErrorAction.REPORT);
|
||||
}
|
||||
|
||||
public static boolean testEncoding(Path zipFile, Charset encoding) throws IOException {
|
||||
try (ZipFile zf = openZipFile(zipFile, encoding)) {
|
||||
return testEncoding(zf, encoding);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean testEncoding(ZipFile zipFile, Charset encoding) throws IOException {
|
||||
Enumeration<ZipArchiveEntry> entries = zipFile.getEntries();
|
||||
CharsetDecoder cd = newCharsetDecoder(encoding);
|
||||
CharBuffer cb = CharBuffer.allocate(32);
|
||||
|
||||
while (entries.hasMoreElements()) {
|
||||
ZipArchiveEntry entry = entries.nextElement();
|
||||
|
||||
if (entry.getGeneralPurposeBit().usesUTF8ForNames()) continue;
|
||||
|
||||
cd.reset();
|
||||
byte[] ba = entry.getRawName();
|
||||
int clen = (int)(ba.length * cd.maxCharsPerByte());
|
||||
if (clen == 0) continue;
|
||||
if (clen <= cb.capacity())
|
||||
((Buffer) cb).clear(); // cast to prevent "java.lang.NoSuchMethodError: java.nio.CharBuffer.clear()Ljava/nio/CharBuffer;" when compiling with Java 9+
|
||||
else
|
||||
cb = CharBuffer.allocate(clen);
|
||||
|
||||
ByteBuffer bb = ByteBuffer.wrap(ba, 0, ba.length);
|
||||
CoderResult cr = cd.decode(bb, cb, true);
|
||||
if (!cr.isUnderflow()) return false;
|
||||
cr = cd.flush(cb);
|
||||
if (!cr.isUnderflow()) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
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 {
|
||||
try (ZipFile zf = openZipFile(zipFile, StandardCharsets.UTF_8)) {
|
||||
return findSuitableEncoding(zf, candidates);
|
||||
}
|
||||
}
|
||||
|
||||
public static Charset findSuitableEncoding(ZipFile zipFile) throws IOException {
|
||||
return findSuitableEncoding(zipFile, Charset.availableCharsets().values());
|
||||
}
|
||||
|
||||
public static Charset findSuitableEncoding(ZipFile zipFile, Collection<Charset> candidates) throws IOException {
|
||||
if (testEncoding(zipFile, StandardCharsets.UTF_8)) return StandardCharsets.UTF_8;
|
||||
if (OperatingSystem.NATIVE_CHARSET != StandardCharsets.UTF_8 && testEncoding(zipFile, OperatingSystem.NATIVE_CHARSET))
|
||||
return OperatingSystem.NATIVE_CHARSET;
|
||||
|
||||
for (Charset charset : candidates)
|
||||
if (charset != null && testEncoding(zipFile, charset))
|
||||
return charset;
|
||||
throw new IOException("Cannot find suitable encoding for the zip.");
|
||||
}
|
||||
|
||||
public static ZipFile openZipFile(Path zipFile) throws IOException {
|
||||
return new ZipFile(Files.newByteChannel(zipFile));
|
||||
}
|
||||
|
||||
public static ZipFile openZipFile(Path zipFile, Charset charset) throws IOException {
|
||||
return new ZipFile(Files.newByteChannel(zipFile), charset.name());
|
||||
}
|
||||
|
||||
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 {
|
||||
return createReadOnlyZipFileSystem(zipFile, null);
|
||||
}
|
||||
|
||||
public static FileSystem createReadOnlyZipFileSystem(Path zipFile, Charset charset) throws IOException {
|
||||
return createZipFileSystem(zipFile, false, false, charset);
|
||||
}
|
||||
|
||||
public static FileSystem createWritableZipFileSystem(Path zipFile) throws IOException {
|
||||
return createWritableZipFileSystem(zipFile, null);
|
||||
}
|
||||
|
||||
public static FileSystem createWritableZipFileSystem(Path zipFile, Charset charset) throws IOException {
|
||||
return createZipFileSystem(zipFile, true, true, charset);
|
||||
}
|
||||
|
||||
public static FileSystem createZipFileSystem(Path zipFile, boolean create, boolean useTempFile, Charset encoding) throws IOException {
|
||||
Map<String, Object> env = new HashMap<>();
|
||||
if (create)
|
||||
env.put("create", "true");
|
||||
if (encoding != null)
|
||||
env.put("encoding", encoding.name());
|
||||
if (useTempFile)
|
||||
env.put("useTempFile", true);
|
||||
try {
|
||||
return ZIPFS_PROVIDER.newFileSystem(zipFile, env);
|
||||
} catch (ZipError error) {
|
||||
// Since Java 8 throws ZipError stupidly
|
||||
throw new ZipException(error.getMessage());
|
||||
} catch (UnsupportedOperationException ex) {
|
||||
throw new ZipException("Not a zip file");
|
||||
} catch (FileSystemNotFoundException ex) {
|
||||
throw new ZipException("Java Environment is broken");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(File zipFile, String name) throws IOException {
|
||||
try (ZipFile s = new ZipFile(zipFile)) {
|
||||
return readTextZipEntry(s, name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(ZipFile zipFile, String name) throws IOException {
|
||||
return IOUtils.readFullyAsString(zipFile.getInputStream(zipFile.getEntry(name)), StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 (ZipFile s = openZipFile(zipFile, encoding)) {
|
||||
return IOUtils.readFullyAsString(s.getInputStream(s.getEntry(name)), StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(File file, String name) {
|
||||
try {
|
||||
return Optional.of(readTextZipEntry(file, name));
|
||||
} catch (IOException | NullPointerException e) {
|
||||
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 | NullPointerException e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
package com.tungsten.fclcore.util.io;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
|
||||
public class Unzipper {
|
||||
private final Path zipFile, dest;
|
||||
private boolean replaceExistentFile = false;
|
||||
private boolean terminateIfSubDirectoryNotExists = false;
|
||||
private String subDirectory = "/";
|
||||
private FileFilter filter = null;
|
||||
private Charset encoding = StandardCharsets.UTF_8;
|
||||
|
||||
/**
|
||||
* Decompress the given zip file to a directory.
|
||||
*
|
||||
* @param zipFile the input zip file to be uncompressed
|
||||
* @param destDir the dest directory to hold uncompressed files
|
||||
*/
|
||||
public Unzipper(Path zipFile, Path destDir) {
|
||||
this.zipFile = zipFile;
|
||||
this.dest = destDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decompress the given zip file to a directory.
|
||||
*
|
||||
* @param zipFile the input zip file to be uncompressed
|
||||
* @param destDir the dest directory to hold uncompressed files
|
||||
*/
|
||||
public Unzipper(File zipFile, File destDir) {
|
||||
this(zipFile.toPath(), destDir.toPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* True if replace the existent files in destination directory,
|
||||
* otherwise those conflict files will be ignored.
|
||||
*/
|
||||
public Unzipper setReplaceExistentFile(boolean replaceExistentFile) {
|
||||
this.replaceExistentFile = replaceExistentFile;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will be called for every entry in the zip file.
|
||||
* Callback returns false if you want leave the specific file uncompressed.
|
||||
*/
|
||||
public Unzipper setFilter(FileFilter filter) {
|
||||
this.filter = filter;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will only uncompress files in the "subDirectory", their path will be also affected.
|
||||
*
|
||||
* For example, if you set subDirectory to /META-INF, files in /META-INF/ will be
|
||||
* uncompressed to the destination directory without creating META-INF folder.
|
||||
*
|
||||
* Default value: "/"
|
||||
*/
|
||||
public Unzipper setSubDirectory(String subDirectory) {
|
||||
this.subDirectory = FileUtils.normalizePath(subDirectory);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Unzipper setEncoding(Charset encoding) {
|
||||
this.encoding = encoding;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Unzipper setTerminateIfSubDirectoryNotExists() {
|
||||
this.terminateIfSubDirectoryNotExists = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decompress the given zip file to a directory.
|
||||
*
|
||||
* @throws IOException if zip file is malformed or filesystem error.
|
||||
*/
|
||||
public void unzip() throws IOException {
|
||||
Files.createDirectories(dest);
|
||||
try (FileSystem fs = CompressingUtils.readonly(zipFile).setEncoding(encoding).setAutoDetectEncoding(true).build()) {
|
||||
Path root = fs.getPath(subDirectory);
|
||||
if (!root.isAbsolute() || (subDirectory.length() > 1 && subDirectory.endsWith("/")))
|
||||
throw new IllegalArgumentException("Subdirectory for unzipper must be absolute");
|
||||
|
||||
if (terminateIfSubDirectoryNotExists && Files.notExists(root))
|
||||
return;
|
||||
|
||||
Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file,
|
||||
BasicFileAttributes attrs) throws IOException {
|
||||
String relativePath = root.relativize(file).toString();
|
||||
Path destFile = dest.resolve(relativePath);
|
||||
if (filter != null && !filter.accept(file, false, destFile, relativePath))
|
||||
return FileVisitResult.CONTINUE;
|
||||
try {
|
||||
Files.copy(file, destFile, replaceExistentFile ? new CopyOption[]{StandardCopyOption.REPLACE_EXISTING} : new CopyOption[]{});
|
||||
} catch (FileAlreadyExistsException e) {
|
||||
if (replaceExistentFile)
|
||||
throw e;
|
||||
}
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectory(Path dir,
|
||||
BasicFileAttributes attrs) throws IOException {
|
||||
String relativePath = root.relativize(dir).toString();
|
||||
Path dirToCreate = dest.resolve(relativePath);
|
||||
if (filter != null && !filter.accept(dir, true, dirToCreate, relativePath))
|
||||
return FileVisitResult.SKIP_SUBTREE;
|
||||
Files.createDirectories(dirToCreate);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public interface FileFilter {
|
||||
boolean accept(Path zipEntry, boolean isDirectory, Path destFile, String entryPath) throws IOException;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
package com.tungsten.fclcore.util.io;
|
||||
|
||||
import com.tungsten.fclcore.util.function.ExceptionalPredicate;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
|
||||
/**
|
||||
* Non thread-safe
|
||||
*/
|
||||
public final class Zipper implements Closeable {
|
||||
|
||||
private final FileSystem fs;
|
||||
|
||||
public Zipper(Path zipFile) throws IOException {
|
||||
this(zipFile, null);
|
||||
}
|
||||
|
||||
public Zipper(Path zipFile, Charset encoding) throws IOException {
|
||||
Files.deleteIfExists(zipFile);
|
||||
fs = CompressingUtils.createWritableZipFileSystem(zipFile, encoding);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
fs.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Compress all the files in sourceDir
|
||||
*
|
||||
* @param source the file in basePath to be compressed
|
||||
* @param rootDir the path of the directory in this zip file.
|
||||
*/
|
||||
public void putDirectory(Path source, String rootDir) throws IOException {
|
||||
putDirectory(source, rootDir, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compress all the files in sourceDir
|
||||
*
|
||||
* @param source the file in basePath to be compressed
|
||||
* @param targetDir the path of the directory in this zip file.
|
||||
* @param filter returns false if you do not want that file or directory
|
||||
*/
|
||||
public void putDirectory(Path source, String targetDir, ExceptionalPredicate<String, IOException> filter) throws IOException {
|
||||
Path root = fs.getPath(targetDir);
|
||||
Files.createDirectories(root);
|
||||
Files.walkFileTree(source, new SimpleFileVisitor<Path>() {
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||
if (".DS_Store".equals(file.getFileName().toString())) {
|
||||
return FileVisitResult.SKIP_SUBTREE;
|
||||
}
|
||||
String relativePath = source.relativize(file).normalize().toString();
|
||||
if (filter != null && !filter.test(relativePath.replace('\\', '/'))) {
|
||||
return FileVisitResult.SKIP_SUBTREE;
|
||||
}
|
||||
Files.copy(file, root.resolve(relativePath), StandardCopyOption.COPY_ATTRIBUTES);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
|
||||
String relativePath = source.relativize(dir).normalize().toString();
|
||||
if (filter != null && !filter.test(relativePath.replace('\\', '/'))) {
|
||||
return FileVisitResult.SKIP_SUBTREE;
|
||||
}
|
||||
Path path = root.resolve(relativePath);
|
||||
if (Files.notExists(path)) {
|
||||
Files.createDirectory(path);
|
||||
}
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void putFile(File file, String path) throws IOException {
|
||||
putFile(file.toPath(), path);
|
||||
}
|
||||
|
||||
public void putFile(Path file, String path) throws IOException {
|
||||
Files.copy(file, fs.getPath(path), StandardCopyOption.COPY_ATTRIBUTES);
|
||||
}
|
||||
|
||||
public void putStream(InputStream in, String path) throws IOException {
|
||||
Files.copy(in, fs.getPath(path), StandardCopyOption.COPY_ATTRIBUTES);
|
||||
}
|
||||
|
||||
public void putTextFile(String text, String path) throws IOException {
|
||||
putTextFile(text, "UTF-8", path);
|
||||
}
|
||||
|
||||
public void putTextFile(String text, String encoding, String pathName) throws IOException {
|
||||
Files.write(fs.getPath(pathName), text.getBytes(encoding));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,9 @@
|
|||
package com.tungsten.fclcore.util.platform;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.charset.UnsupportedCharsetException;
|
||||
|
||||
public enum OperatingSystem {
|
||||
/**
|
||||
* Microsoft Windows.
|
||||
|
@ -28,4 +32,31 @@ public enum OperatingSystem {
|
|||
return checkedName;
|
||||
}
|
||||
|
||||
public static final Charset NATIVE_CHARSET;
|
||||
|
||||
static {
|
||||
String nativeEncoding = System.getProperty("native.encoding");
|
||||
String hmclNativeEncoding = System.getProperty("fcl.native.encoding");
|
||||
Charset nativeCharset = Charset.defaultCharset();
|
||||
|
||||
try {
|
||||
if (hmclNativeEncoding != null) {
|
||||
nativeCharset = Charset.forName(hmclNativeEncoding);
|
||||
} else {
|
||||
if (nativeEncoding != null && !nativeEncoding.equalsIgnoreCase(nativeCharset.name())) {
|
||||
nativeCharset = Charset.forName(nativeEncoding);
|
||||
}
|
||||
|
||||
if (nativeCharset == StandardCharsets.UTF_8 || nativeCharset == StandardCharsets.US_ASCII) {
|
||||
nativeCharset = StandardCharsets.UTF_8;
|
||||
} else if ("GBK".equalsIgnoreCase(nativeCharset.name()) || "GB2312".equalsIgnoreCase(nativeCharset.name())) {
|
||||
nativeCharset = Charset.forName("GB18030");
|
||||
}
|
||||
}
|
||||
} catch (UnsupportedCharsetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
NATIVE_CHARSET = nativeCharset;
|
||||
}
|
||||
|
||||
}
|
|
@ -10,6 +10,9 @@ dependencyResolutionManagement {
|
|||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
maven {
|
||||
url "https://jitpack.io"
|
||||
}
|
||||
}
|
||||
}
|
||||
rootProject.name = "Fold Craft Launcher"
|
||||
|
|
Loading…
Reference in New Issue