mirror of
https://github.com/HMCL-dev/HMCL.git
synced 2024-12-27 07:10:41 +08:00
Fixed logging spaces and tabs missing, unclickable version item, removing 'logging' element when installing forge and liteloader
This commit is contained in:
parent
e70226afba
commit
3b4359f7eb
@ -51,9 +51,9 @@ import com.sun.javafx.scene.layout.region.BorderStyleConverter.HIDDEN
|
||||
*/
|
||||
@Throws(IOException::class, JsonParseException::class)
|
||||
fun readHMCLModpackManifest(f: File): Modpack {
|
||||
val manifestJson = readTextFromZipFile(f, "modpack.json")
|
||||
val manifestJson = f.readTextZipEntry("modpack.json")
|
||||
val manifest = GSON.fromJson<Modpack>(manifestJson) ?: throw JsonParseException("`modpack.json` not found. $f is not a valid HMCL modpack.")
|
||||
val gameJson = readTextFromZipFile(f, "minecraft/pack.json")
|
||||
val gameJson = f.readTextZipEntry("minecraft/pack.json")
|
||||
val game = GSON.fromJson<Version>(gameJson) ?: throw JsonParseException("`minecraft/pack.json` not found. $f iot a valid HMCL modpack.")
|
||||
return if (game.jar == null)
|
||||
if (manifest.gameVersion.isNullOrBlank()) throw JsonParseException("Cannot recognize the game version of modpack $f.")
|
||||
@ -71,7 +71,7 @@ class HMCLModpackInstallTask(profile: Profile, private val zipFile: File, privat
|
||||
|
||||
init {
|
||||
check(!repository.hasVersion(name), { "Version $name already exists." })
|
||||
val json = readTextFromZipFile(zipFile, "minecraft/pack.json")
|
||||
val json = zipFile.readTextZipEntry("minecraft/pack.json")
|
||||
var version = GSON.fromJson<Version>(json)!!
|
||||
version = version.copy(jar = null)
|
||||
dependents += dependency.gameBuilder().name(name).gameVersion(modpack.gameVersion!!).buildAsync()
|
||||
@ -81,10 +81,7 @@ class HMCLModpackInstallTask(profile: Profile, private val zipFile: File, privat
|
||||
private val run = repository.getRunDirectory(name)
|
||||
|
||||
override fun execute() {
|
||||
unzipSubDirectory(zipFile, run, "minecraft/", false)
|
||||
val json = run.resolve("pack.json")
|
||||
if (repository.getVersionJson(name) != json)
|
||||
json.delete()
|
||||
zipFile.uncompressTo(run, "minecraft/", callback = { it != "minecraft/pack.json" }, ignoreExistentFile = false)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -171,7 +171,10 @@ object Settings {
|
||||
else {
|
||||
System.setProperty("http.proxyHost", proxyHost)
|
||||
System.setProperty("http.proxyPort", proxyPort)
|
||||
proxy = Proxy(proxyType, InetSocketAddress(host, port))
|
||||
if (proxyType == Proxy.Type.DIRECT)
|
||||
proxy = Proxy.NO_PROXY
|
||||
else
|
||||
proxy = Proxy(proxyType, InetSocketAddress(host, port))
|
||||
|
||||
val user = proxyUser
|
||||
val pass = proxyPass
|
||||
|
@ -30,13 +30,11 @@ import javafx.scene.layout.StackPane
|
||||
import javafx.scene.web.WebEngine
|
||||
import javafx.scene.web.WebView
|
||||
import javafx.stage.Stage
|
||||
import netscape.javascript.JSObject
|
||||
import org.jackhuang.hmcl.game.LauncherHelper
|
||||
import org.jackhuang.hmcl.i18n
|
||||
import org.jackhuang.hmcl.setting.Settings
|
||||
import org.jackhuang.hmcl.util.Log4jLevel
|
||||
import org.jackhuang.hmcl.util.inc
|
||||
import org.jackhuang.hmcl.util.onChange
|
||||
import org.jackhuang.hmcl.util.readFullyAsString
|
||||
import org.jackhuang.hmcl.util.*
|
||||
import org.w3c.dom.Document
|
||||
import org.w3c.dom.Node
|
||||
import java.util.concurrent.Callable
|
||||
@ -59,7 +57,10 @@ class LogWindow : Stage() {
|
||||
|
||||
fun logLine(line: String, level: Log4jLevel) {
|
||||
impl.body.appendChild(impl.engine.document.createElement("div").apply {
|
||||
textContent = line
|
||||
// a <pre> element to prevent multiple spaces and tabs being removed.
|
||||
appendChild(impl.engine.document.createElement("pre").apply {
|
||||
textContent = line
|
||||
})
|
||||
})
|
||||
impl.engine.executeScript("checkNewLog(\"${level.name.toLowerCase()}\");scrollToBottom();")
|
||||
|
||||
|
@ -72,7 +72,7 @@ class ModpackPage(private val controller: WizardController): StackPane(), Wizard
|
||||
lblName.text = manifest!!.name
|
||||
lblVersion.text = manifest!!.version
|
||||
lblAuthor.text = manifest!!.author
|
||||
txtModpackName.text = manifest!!.name + "-" + manifest!!.version
|
||||
txtModpackName.text = manifest!!.name + (if (manifest!!.version.isNullOrBlank()) "" else ("-" + manifest!!.version))
|
||||
} catch (e: Exception) {
|
||||
// TODO
|
||||
txtModpackName.text = i18n("modpack.task.install.error")
|
||||
|
@ -5,14 +5,13 @@
|
||||
<?import javafx.scene.control.ScrollPane?>
|
||||
<fx:root
|
||||
maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity"
|
||||
styleClass="transparent" type="StackPane"
|
||||
styleClass="transparent" type="StackPane" pickOnBounds="false"
|
||||
xmlns="http://javafx.com/javafx/8.0.112" xmlns:fx="http://javafx.com/fxml/1">
|
||||
<ScrollPane fitToHeight="true" fitToWidth="true" fx:id="scrollPane" hbarPolicy="NEVER">
|
||||
<JFXMasonryPane fx:id="masonryPane" HSpacing="3" VSpacing="3" cellWidth="182" cellHeight="160">
|
||||
</JFXMasonryPane>
|
||||
</ScrollPane>
|
||||
<VBox style="-fx-padding: 15;" spacing="15" pickOnBounds="false" alignment="BOTTOM_RIGHT">
|
||||
<!--JFXSpinner fx:id="spinner" style="-fx-radius:10" styleClass="materialDesign-purple, first-spinner" /-->
|
||||
<JFXButton prefWidth="40" prefHeight="40" buttonType="RAISED" fx:id="btnRefresh"
|
||||
style="-fx-background-color:#5264AE;-fx-background-radius: 50px;">
|
||||
<graphic>
|
||||
|
@ -10,9 +10,9 @@
|
||||
<?import com.jfoenix.controls.JFXRadioButton?>
|
||||
<fx:root xmlns="http://javafx.com/javafx"
|
||||
xmlns:fx="http://javafx.com/fxml"
|
||||
type="StackPane">
|
||||
<VBox fx:id="content">
|
||||
<StackPane fx:id="header" VBox.vgrow="ALWAYS">
|
||||
type="StackPane" pickOnBounds="false">
|
||||
<VBox fx:id="content" pickOnBounds="false">
|
||||
<StackPane fx:id="header" VBox.vgrow="ALWAYS" pickOnBounds="false">
|
||||
<BorderPane>
|
||||
<top>
|
||||
<HBox alignment="CENTER_RIGHT">
|
||||
@ -26,7 +26,7 @@
|
||||
</center>
|
||||
</BorderPane>
|
||||
</StackPane>
|
||||
<StackPane fx:id="body" style="-fx-background-radius: 0 0 2 2; -fx-background-color: rgb(255,255,255,0.87); -fx-padding: 8;" minHeight="40">
|
||||
<StackPane fx:id="body" style="-fx-background-radius: 0 0 2 2; -fx-background-color: rgb(255,255,255,0.87); -fx-padding: 8;" minHeight="40" pickOnBounds="false">
|
||||
<BorderPane>
|
||||
<left>
|
||||
<HBox spacing="8">
|
||||
|
@ -9,7 +9,7 @@
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
div {
|
||||
div > pre {
|
||||
font: ${FONT};
|
||||
margin: 0px;
|
||||
padding: 2px;
|
||||
|
@ -43,10 +43,10 @@ object BMCLAPIDownloadProvider : DownloadProvider() {
|
||||
}
|
||||
|
||||
override fun injectURL(baseURL: String): String = baseURL
|
||||
.replace("https://launchermeta.mojang.com", "http://bmclapi2.bangbang93.com")
|
||||
.replace("https://launcher.mojang.com", "http://bmclapi2.bangbang93.com")
|
||||
.replace("https://libraries.minecraft.net", "http://bmclapi2.bangbang93.com/libraries")
|
||||
.replace("http://files.minecraftforge.net/maven", "http://bmclapi2.bangbang93.com/maven")
|
||||
.replace("http://dl.liteloader.com/versions/versions.json", "http://bmclapi2.bangbang93.com/maven/com/mumfrey/liteloader/versions.json")
|
||||
.replace("http://dl.liteloader.com/versions", "http://bmclapi2.bangbang93.com/maven")
|
||||
.replace("https://launchermeta.mojang.com", "https://bmclapi2.bangbang93.com")
|
||||
.replace("https://launcher.mojang.com", "https://bmclapi2.bangbang93.com")
|
||||
.replace("https://libraries.minecraft.net", "https://bmclapi2.bangbang93.com/libraries")
|
||||
.replace("http://files.minecraftforge.net/maven", "https://bmclapi2.bangbang93.com/maven")
|
||||
.replace("http://dl.liteloader.com/versions/versions.json", "httsp://bmclapi2.bangbang93.com/maven/com/mumfrey/liteloader/versions.json")
|
||||
.replace("http://dl.liteloader.com/versions", "https://bmclapi2.bangbang93.com/maven")
|
||||
}
|
@ -46,8 +46,6 @@ object MojangDownloadProvider : DownloadProvider() {
|
||||
override fun injectURL(baseURL: String): String {
|
||||
if (baseURL.endsWith("net/minecraftforge/forge/json"))
|
||||
return baseURL
|
||||
else if (Locale.getDefault() == Locale.CHINA)
|
||||
return baseURL.replace("http://files.minecraftforge.net/maven", "http://maven.aliyun.com/nexus/content/groups/public");
|
||||
else
|
||||
return baseURL.replace("http://files.minecraftforge.net/maven", "http://ftb.cursecdn.com/FTB2/maven")
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ class ForgeInstallTask(private val dependencyManager: DefaultDependencyManager,
|
||||
val versionProvider = SimpleVersionProvider()
|
||||
versionProvider.addVersion(version)
|
||||
|
||||
result = installProfile.versionInfo!!.copy(inheritsFrom = version.id).resolve(versionProvider).copy(id = version.id)
|
||||
result = installProfile.versionInfo!!.copy(inheritsFrom = version.id).resolve(versionProvider).copy(id = version.id, logging = emptyMap())
|
||||
dependencies += GameLibrariesTask(dependencyManager, installProfile.versionInfo)
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,8 @@ class LiteLoaderInstallTask(private val dependencyManager: DefaultDependencyMana
|
||||
result = version.copy(
|
||||
mainClass = "net.minecraft.launchwrapper.Launch",
|
||||
minecraftArguments = version.minecraftArguments + " --tweakClass " + remote.tag.tweakClass,
|
||||
libraries = merge(tempVersion.libraries, version.libraries)
|
||||
libraries = merge(tempVersion.libraries, version.libraries),
|
||||
logging = emptyMap()
|
||||
)
|
||||
dependencies += GameLibrariesTask(dependencyManager, tempVersion)
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ open class Library(
|
||||
|
||||
companion object LibrarySerializer : JsonDeserializer<Library>, JsonSerializer<Library> {
|
||||
fun fromName(name: String, url: String? = null, downloads: LibrariesDownloadInfo? = null, extract: ExtractRules? = null, natives: Map<OS, String>? = null, rules: List<CompatibilityRule>? = null): Library {
|
||||
val arr = name.split(":".toRegex(), 3)
|
||||
val arr = name.split(":".toRegex(), 4)
|
||||
if (arr.size != 3 && arr.size != 4)
|
||||
throw IllegalArgumentException("Library name is malformed. Correct example: group:artifact:version.")
|
||||
return Library(
|
||||
|
@ -214,11 +214,11 @@ open class DefaultLauncher(repository: GameRepository, versionId: String, accoun
|
||||
open fun decompressNatives() {
|
||||
version.libraries.filter { it.isNative }.forEach { library ->
|
||||
@Suppress("UNNECESSARY_NOT_NULL_ASSERTION")
|
||||
unzip(zip = repository.getLibraryFile(version, library),
|
||||
repository.getLibraryFile(version, library).uncompressTo(
|
||||
dest = native,
|
||||
callback = if (library.extract == null) null
|
||||
else library.extract!!::shouldExtract,
|
||||
ignoreExistsFile = false)
|
||||
ignoreExistentFile = false)
|
||||
}
|
||||
}
|
||||
|
||||
@ -230,10 +230,13 @@ open class DefaultLauncher(repository: GameRepository, versionId: String, accoun
|
||||
decompressNatives()
|
||||
|
||||
if (options.precalledCommand != null && options.precalledCommand.isNotBlank()) {
|
||||
val process = Runtime.getRuntime().exec(options.precalledCommand)
|
||||
ignoreException {
|
||||
if (process.isAlive)
|
||||
process.waitFor()
|
||||
try {
|
||||
val process = Runtime.getRuntime().exec(options.precalledCommand)
|
||||
if (process.isAlive)
|
||||
process.waitFor()
|
||||
} catch (e: IOException) {
|
||||
// TODO: alert precalledCommand is wrong.
|
||||
// rethrow InterruptedException
|
||||
}
|
||||
}
|
||||
|
||||
@ -287,6 +290,14 @@ open class DefaultLauncher(repository: GameRepository, versionId: String, accoun
|
||||
}
|
||||
|
||||
private fun startMonitors(managedProcess: ManagedProcess, processListener: ProcessListener, isDaemon: Boolean = true) {
|
||||
val enablesLoggingInfo = version.logging?.containsKey(DownloadType.CLIENT) ?: false
|
||||
if (enablesLoggingInfo)
|
||||
startMonitorsWithLoggingInfo(managedProcess, processListener, isDaemon)
|
||||
else
|
||||
startMonitorsWithoutLoggingInfo(managedProcess, processListener, isDaemon)
|
||||
}
|
||||
|
||||
private fun startMonitorsWithLoggingInfo(managedProcess: ManagedProcess, processListener: ProcessListener, isDaemon: Boolean = true) {
|
||||
processListener.setProcess(managedProcess)
|
||||
val logHandler = Log4jHandler { line, level -> processListener.onLog(line, level); managedProcess.lines += line }.apply { start() }
|
||||
managedProcess.relatedThreads += logHandler
|
||||
@ -297,6 +308,15 @@ open class DefaultLauncher(repository: GameRepository, versionId: String, accoun
|
||||
managedProcess.relatedThreads += thread(name = "exit-waiter", isDaemon = isDaemon, block = ExitWaiter(managedProcess, listOf(stdout, stderr), { exitCode, exitType -> logHandler.onStopped(); processListener.onExit(exitCode, exitType) })::run)
|
||||
}
|
||||
|
||||
private fun startMonitorsWithoutLoggingInfo(managedProcess: ManagedProcess, processListener: ProcessListener, isDaemon: Boolean = true) {
|
||||
processListener.setProcess(managedProcess)
|
||||
val stdout = thread(name = "stdout-pump", isDaemon = isDaemon, block = StreamPump(managedProcess.process.inputStream, { processListener.onLog(it + OS.LINE_SEPARATOR, Log4jLevel.guessLevel(it) ?: Log4jLevel.INFO); managedProcess.lines += it })::run)
|
||||
managedProcess.relatedThreads += stdout
|
||||
val stderr = thread(name = "stderr-pump", isDaemon = isDaemon, block = StreamPump(managedProcess.process.errorStream, { processListener.onLog(it + OS.LINE_SEPARATOR, Log4jLevel.ERROR); managedProcess.lines += it })::run)
|
||||
managedProcess.relatedThreads += stderr
|
||||
managedProcess.relatedThreads += thread(name = "exit-waiter", isDaemon = isDaemon, block = ExitWaiter(managedProcess, listOf(stdout, stderr), { exitCode, exitType -> processListener.onExit(exitCode, exitType) })::run)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val LAUNCH_ASYNC_ID = "process"
|
||||
}
|
||||
|
@ -106,7 +106,7 @@ class CurseForgeModpackManifestFile (
|
||||
*/
|
||||
@Throws(IOException::class, JsonParseException::class)
|
||||
fun readCurseForgeModpackManifest(f: File): Modpack {
|
||||
val json = readTextFromZipFile(f, "manifest.json")
|
||||
val json = f.readTextZipEntry("manifest.json")
|
||||
val manifest = GSON.fromJson<CurseForgeModpackManifest>(json)
|
||||
?: throw JsonParseException("`manifest.json` not found. Not a valid CurseForge modpack.")
|
||||
return Modpack(
|
||||
@ -114,7 +114,7 @@ fun readCurseForgeModpackManifest(f: File): Modpack {
|
||||
version = manifest.version,
|
||||
author = manifest.author,
|
||||
gameVersion = manifest.minecraft.gameVersion,
|
||||
description = readTextFromZipFileQuietly(f, "modlist.html") ?: "No description",
|
||||
description = f.readTextZipEntryQuietly("modlist.html") ?: "No description",
|
||||
manifest = manifest)
|
||||
}
|
||||
|
||||
@ -147,7 +147,7 @@ class CurseForgeModpackInstallTask(private val dependencyManager: DefaultDepende
|
||||
}
|
||||
|
||||
override fun execute() {
|
||||
unzipSubDirectory(zipFile, run, manifest.overrides)
|
||||
zipFile.uncompressTo(run, subDirectory = manifest.overrides)
|
||||
|
||||
var finished = 0
|
||||
for (f in manifest.files) {
|
||||
|
@ -42,7 +42,7 @@ class InstancePatch @JvmOverloads constructor(
|
||||
val libraries: List<Library> = emptyList()
|
||||
)
|
||||
|
||||
class InstanceConfiguration(contentStream: InputStream) {
|
||||
class InstanceConfiguration(defaultName: String, contentStream: InputStream) {
|
||||
/**
|
||||
* The instance's name
|
||||
*/
|
||||
@ -183,15 +183,17 @@ class InstanceConfiguration(contentStream: InputStream) {
|
||||
showConsole = p.getProperty("ShowConsole") == "true"
|
||||
showConsoleOnError = p.getProperty("ShowConsoleOnError") == "true"
|
||||
wrapperCommand = p.getProperty("WrapperCommand")
|
||||
name = p.getProperty("name")
|
||||
notes = p.getProperty("notes")
|
||||
name = defaultName
|
||||
notes = p.getProperty("notes") ?: ""
|
||||
}
|
||||
}
|
||||
|
||||
fun readMMCModpackManifest(f: File): Modpack {
|
||||
ZipFile(f).use { zipFile ->
|
||||
val entry = zipFile.getEntry("instance.cfg") ?: throw IOException("`instance.cfg` not found, $f is not a valid MultiMC modpack.")
|
||||
val cfg = InstanceConfiguration(zipFile.getInputStream(entry))
|
||||
val firstEntry = zipFile.entries.nextElement()
|
||||
val name = firstEntry.name.substringBefore("/")
|
||||
val entry = zipFile.getEntry("$name/instance.cfg") ?: throw IOException("`instance.cfg` not found, $f is not a valid MultiMC modpack.")
|
||||
val cfg = InstanceConfiguration(name, zipFile.getInputStream(entry))
|
||||
return Modpack(
|
||||
name = cfg.name,
|
||||
version = "",
|
||||
@ -217,12 +219,12 @@ class MMCModpackInstallTask(private val dependencyManager: DefaultDependencyMana
|
||||
|
||||
override fun execute() {
|
||||
var version = repository.readVersionJson(name)!!
|
||||
unzipSubDirectory(zipFile, run, "minecraft/", false)
|
||||
zipFile.uncompressTo(run, subDirectory = "${manifest.name}/minecraft/", ignoreExistentFile = false, allowStoredEntriesWithDataDescriptor = true)
|
||||
|
||||
ZipFile(zipFile).use { zip ->
|
||||
for (entry in zip.entries) {
|
||||
// ensure that this entry is in folder 'patches' and is a json file.
|
||||
if (!entry.isDirectory && entry.name.startsWith("patches/") && entry.name.endsWith(".json")) {
|
||||
if (!entry.isDirectory && entry.name.startsWith("${manifest.name}/patches/") && entry.name.endsWith(".json")) {
|
||||
val patch = GSON.fromJson<InstancePatch>(zip.getInputStream(entry).readFullyAsString())!!
|
||||
val args = StringBuilder(version.minecraftArguments)
|
||||
for (arg in patch.tweakers)
|
||||
|
@ -34,21 +34,22 @@ import java.io.IOException
|
||||
*/
|
||||
@JvmOverloads
|
||||
@Throws(IOException::class)
|
||||
fun zip(src: File, destZip: File, pathNameCallback: ((String, Boolean) -> String?)? = null) {
|
||||
fun File.zipTo(destZip: File, pathNameCallback: ((String, Boolean) -> String?)? = null) {
|
||||
ZipArchiveOutputStream(destZip.outputStream()).use { zos ->
|
||||
val basePath: String
|
||||
if (src.isDirectory)
|
||||
basePath = src.path
|
||||
if (this.isDirectory)
|
||||
basePath = this.path
|
||||
else
|
||||
//直接压缩单个文件时,取父目录
|
||||
basePath = src.parent
|
||||
zipFile(src, basePath, zos, pathNameCallback)
|
||||
//直接压缩单个文件时,取父目录
|
||||
basePath = this.parent
|
||||
zipFile(this, basePath, zos, pathNameCallback)
|
||||
zos.closeArchiveEntry()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Zip file.
|
||||
*
|
||||
* @param src source directory to be compressed.
|
||||
* @param basePath the file directory to be compressed, if [src] is a file, this is the parent directory of [src]
|
||||
* @param zos the [ZipOutputStream] of dest zip file.
|
||||
@ -92,69 +93,21 @@ private fun zipFile(src: File,
|
||||
|
||||
/**
|
||||
* Decompress the given zip file to a directory.
|
||||
* @param zip the source zip file.
|
||||
* @param dest the dest directory.
|
||||
* @param callback will be called for every entry in the zip file, returns false if you dont want this file unzipped.
|
||||
* @throws IOException
|
||||
*/
|
||||
@JvmOverloads
|
||||
@Throws(IOException::class)
|
||||
fun unzip(zip: File, dest: File, callback: ((String) -> Boolean)? = null, ignoreExistsFile: Boolean = true) {
|
||||
val buf = ByteArray(1024)
|
||||
dest.mkdirs()
|
||||
ZipArchiveInputStream(zip.inputStream()).use { zipFile ->
|
||||
if (zip.exists()) {
|
||||
val strPath = dest.absolutePath
|
||||
while (true) {
|
||||
val zipEnt = zipFile.nextEntry ?: break
|
||||
var strtemp: String
|
||||
var gbkPath = zipEnt.name
|
||||
if (callback != null)
|
||||
if (!callback.invoke(gbkPath))
|
||||
continue
|
||||
if (zipEnt.isDirectory) {
|
||||
strtemp = strPath + File.separator + gbkPath
|
||||
val dir = File(strtemp)
|
||||
dir.mkdirs()
|
||||
} else {
|
||||
//读写文件
|
||||
gbkPath = zipEnt.name
|
||||
strtemp = strPath + File.separator + gbkPath
|
||||
//建目录
|
||||
val strsubdir = gbkPath
|
||||
for (i in 0 until strsubdir.length)
|
||||
if (strsubdir.substring(i, i + 1).equals("/", ignoreCase = true)) {
|
||||
val temp = strPath + File.separator + strsubdir.substring(0, i)
|
||||
val subdir = File(temp)
|
||||
if (!subdir.exists())
|
||||
subdir.mkdir()
|
||||
}
|
||||
if (ignoreExistsFile && File(strtemp).exists())
|
||||
continue
|
||||
File(strtemp).outputStream().use({ fos ->
|
||||
zipFile.copyTo(fos, buf)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decompress the subdirectory of given zip file.
|
||||
* @param zip the source zip file.
|
||||
*
|
||||
* @param dest the dest directory.
|
||||
* @param subDirectory the subdirectory of the zip file to be decompressed.
|
||||
* @param callback will be called for every entry in the zip file, returns false if you dont want this file being uncompressed.
|
||||
* @param ignoreExistentFile true if skip all existent files.
|
||||
* @param allowStoredEntriesWithDataDescriptor whether the zip stream will try to read STORED entries that use a data descriptor
|
||||
* @throws IOException
|
||||
*/
|
||||
@JvmOverloads
|
||||
@Throws(IOException::class)
|
||||
fun unzipSubDirectory(zip: File, dest: File, subDirectory: String, ignoreExistentFile: Boolean = true) {
|
||||
fun File.uncompressTo(dest: File, subDirectory: String = "", callback: ((String) -> Boolean)? = null, ignoreExistentFile: Boolean = true, allowStoredEntriesWithDataDescriptor: Boolean = false) {
|
||||
val buf = ByteArray(1024)
|
||||
dest.mkdirs()
|
||||
ZipArchiveInputStream(zip.inputStream()).use { zipFile ->
|
||||
if (zip.exists()) {
|
||||
ZipArchiveInputStream(this.inputStream(), null, true, allowStoredEntriesWithDataDescriptor).use { zipFile ->
|
||||
if (this.exists()) {
|
||||
val strPath = dest.absolutePath
|
||||
while (true) {
|
||||
val zipEnt = zipFile.nextEntry ?: break
|
||||
@ -166,13 +119,18 @@ fun unzipSubDirectory(zip: File, dest: File, subDirectory: String, ignoreExisten
|
||||
gbkPath = gbkPath.substring(subDirectory.length)
|
||||
if (gbkPath.startsWith("/") || gbkPath.startsWith("\\")) gbkPath = gbkPath.substring(1)
|
||||
strtemp = strPath + File.separator + gbkPath
|
||||
|
||||
if (callback != null)
|
||||
if (!callback.invoke(gbkPath))
|
||||
continue
|
||||
|
||||
if (zipEnt.isDirectory) {
|
||||
val dir = File(strtemp)
|
||||
dir.mkdirs()
|
||||
} else {
|
||||
//建目录
|
||||
val strsubdir = gbkPath
|
||||
for (i in 0..strsubdir.length - 1)
|
||||
for (i in 0 until strsubdir.length)
|
||||
if (strsubdir.substring(i, i + 1).equals("/", ignoreCase = true)) {
|
||||
val temp = strPath + File.separator + strsubdir.substring(0, i)
|
||||
val subdir = File(temp)
|
||||
@ -194,14 +152,14 @@ fun unzipSubDirectory(zip: File, dest: File, subDirectory: String, ignoreExisten
|
||||
* Read the text content of a file in zip.
|
||||
*
|
||||
* @param f the zip file
|
||||
* @param location the location of the text in zip file, something like A/B/C/D.txt
|
||||
* @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 content of given file.
|
||||
*/
|
||||
@Throws(IOException::class)
|
||||
fun readTextFromZipFile(f: File, location: String): String {
|
||||
ZipFile(f).use { zipFile ->
|
||||
val entry = zipFile.getEntry(location) ?: throw IOException("`$location` not found.")
|
||||
fun File.readTextZipEntry(name: String): String {
|
||||
ZipFile(this).use { zipFile ->
|
||||
val entry = zipFile.getEntry(name) ?: throw IOException("`$name` not found.")
|
||||
return zipFile.getInputStream(entry).readFullyAsString()
|
||||
}
|
||||
}
|
||||
@ -213,10 +171,9 @@ fun readTextFromZipFile(f: File, location: String): String {
|
||||
* @param location the location of the text in zip file, something like A/B/C/D.txt
|
||||
* @return the content of given file.
|
||||
*/
|
||||
fun readTextFromZipFileQuietly(f: File, location: String): String? {
|
||||
fun File.readTextZipEntryQuietly(location: String) =
|
||||
try {
|
||||
return readTextFromZipFile(f, location)
|
||||
readTextZipEntry(location)
|
||||
} catch (e: IOException) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
null
|
||||
}
|
Loading…
Reference in New Issue
Block a user