Skip to content

Commit 6b39ae3

Browse files
committed
massively improve world extraction
1 parent 2d5e3c9 commit 6b39ae3

File tree

2 files changed

+38
-24
lines changed

2 files changed

+38
-24
lines changed

src/main/kotlin/dev/dediamondpro/resourcify/gui/projectpage/VersionWrapper.kt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,8 @@ class VersionWrapper(private val version: IVersion, private val type: ProjectTyp
4747
file = File(downloadFolder, Utils.incrementFileName(file.name))
4848
}
4949
val sourceFile = it.toFile()
50-
DownloadManager.extractZip(sourceFile, file)
51-
if (sourceFile.canWrite()) {
52-
sourceFile.delete()
50+
DownloadManager.extractWorldZip(sourceFile, file)
51+
if (!sourceFile.delete()) {
5352
Constants.LOGGER.warn("Could not delete world file '$it'.")
5453
}
5554
} else {

src/main/kotlin/dev/dediamondpro/resourcify/util/DownloadManager.kt

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,14 @@ package dev.dediamondpro.resourcify.util
1919

2020
import dev.dediamondpro.resourcify.Constants
2121
import dev.dediamondpro.resourcify.platform.Platform
22+
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry
23+
import org.apache.commons.compress.archivers.zip.ZipFile
2224
import java.io.File
2325
import java.net.URI
2426
import java.nio.file.Files
2527
import java.nio.file.StandardCopyOption
28+
import java.util.Stack
2629
import java.util.concurrent.CompletableFuture
27-
import java.util.zip.ZipEntry
28-
import java.util.zip.ZipFile
2930

3031
object DownloadManager {
3132
private val tempFolder = Platform.getFileInGameDir("resourcify-temp")
@@ -91,7 +92,7 @@ object DownloadManager {
9192
}
9293
if (queuedDownload.extract) {
9394
val targetFolder = queuedDownload.file
94-
extractZip(tempFile, targetFolder)
95+
extractWorldZip(tempFile, targetFolder)
9596
} else {
9697
Files.move(tempFile.toPath(), queuedDownload.file.toPath(), StandardCopyOption.REPLACE_EXISTING)
9798
}
@@ -107,35 +108,49 @@ object DownloadManager {
107108
}, tempFile)
108109
}
109110

110-
fun extractZip(zipFile: File, dest: File) {
111+
fun extractWorldZip(zipFile: File, dest: File) {
111112
// If all content is actually inside another folder inside the zip file, try to find this folder
112113
// We do this by checking if there is only one folder at the root, and then take this folder
113114
dest.mkdirs()
115+
116+
// Use the deprecated constructor since 1.20.1 uses an older version of the commons compress library
114117
ZipFile(zipFile).use { zip ->
115-
// If all content is actually inside another folder inside the zip file, try to find this folder
116-
// We do this by checking if there is only one folder at the root, and then take this folder
118+
// For worlds (which is the only thing currently using this) level.dat should be at the root extracted
119+
// folder, every file not in the same folder or a sub folder of level.dat will be ignored
117120
var prefixToRemove: String? = null
118-
for (entry in zip.entries()) {
119-
val firstFolder = entry.name.substringBefore("/", "")
120-
// Could be readme file, license file, ...
121-
if (firstFolder.isEmpty()) {
122-
continue
123-
}
124-
if (prefixToRemove == null) {
125-
prefixToRemove = "$firstFolder/"
126-
} else if (prefixToRemove != "$firstFolder/") {
127-
prefixToRemove = null
121+
122+
// Prefix finding pass
123+
val entriesToExtract = Stack<ZipArchiveEntry>()
124+
val entries = zip.entries
125+
while (entries.hasMoreElements()) {
126+
val entry = entries.nextElement()
127+
entriesToExtract.push(entry)
128+
129+
val fileName = entry.name.substringAfterLast("/")
130+
if (fileName == "level.dat") {
131+
prefixToRemove = entry.name.substringBeforeLast("/")
132+
if (prefixToRemove.isEmpty()) {
133+
prefixToRemove = null
134+
} else {
135+
prefixToRemove += "/"
136+
}
128137
break
129138
}
130139
}
131140

132-
zip.entries().asSequence().forEach { entry ->
133-
// Remove prefix so when a zip contains a folder which contains the actual files,
134-
// this will handle it
141+
// Extracting pass
142+
while (entriesToExtract.isNotEmpty() || entries.hasMoreElements()) {
143+
val entry = if (entriesToExtract.isNotEmpty()) entriesToExtract.pop() else entries.nextElement()
144+
145+
if (prefixToRemove != null && !entry.name.startsWith(prefixToRemove)) {
146+
// Filter out files
147+
continue
148+
}
149+
135150
val entryFile = resolvePath(entry, dest, prefixToRemove)
136151
if (entry.isDirectory) {
137152
entryFile.mkdirs()
138-
return@forEach
153+
continue
139154
} else {
140155
entryFile.parentFile.mkdirs()
141156
}
@@ -147,7 +162,7 @@ object DownloadManager {
147162
}
148163
}
149164

150-
private fun resolvePath(entry: ZipEntry, targetDir: File, prefix: String?): File {
165+
private fun resolvePath(entry: ZipArchiveEntry, targetDir: File, prefix: String?): File {
151166
val entryName = entry.name.let { if (prefix != null) it.removePrefix(prefix) else it }
152167
val destination = targetDir.resolve(entryName).normalize()
153168
if (!destination.absolutePath.startsWith(targetDir.normalize().absolutePath)) {

0 commit comments

Comments
 (0)