@@ -19,13 +19,14 @@ package dev.dediamondpro.resourcify.util
1919
2020import dev.dediamondpro.resourcify.Constants
2121import dev.dediamondpro.resourcify.platform.Platform
22+ import org.apache.commons.compress.archivers.zip.ZipArchiveEntry
23+ import org.apache.commons.compress.archivers.zip.ZipFile
2224import java.io.File
2325import java.net.URI
2426import java.nio.file.Files
2527import java.nio.file.StandardCopyOption
28+ import java.util.Stack
2629import java.util.concurrent.CompletableFuture
27- import java.util.zip.ZipEntry
28- import java.util.zip.ZipFile
2930
3031object 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