From 0a95ad9f53406f8e5c79bff2c6ce8ba79282e313 Mon Sep 17 00:00:00 2001 From: Radek Davidek Date: Fri, 16 Jan 2026 18:30:28 +0100 Subject: [PATCH] added sup[port for more archivers --- pom.xml | 30 ++++ .../java/com/kfmanager/ui/FilePanelTab.java | 157 +++++++++++++++--- 2 files changed, 162 insertions(+), 25 deletions(-) diff --git a/pom.xml b/pom.xml index 1ac76cc..21f1756 100644 --- a/pom.xml +++ b/pom.xml @@ -21,6 +21,23 @@ + + org.apache.maven.plugins + maven-dependency-plugin + 3.9.0 + + + install + + copy-dependencies + + + ${project.build.directory}/lib + runtime + + + + org.apache.maven.plugins maven-compiler-plugin @@ -68,4 +85,17 @@ + + + + org.apache.commons + commons-compress + 1.21 + + + com.github.junrar + junrar + 7.4.1 + + diff --git a/src/main/java/com/kfmanager/ui/FilePanelTab.java b/src/main/java/com/kfmanager/ui/FilePanelTab.java index 14f7e05..5fa4432 100644 --- a/src/main/java/com/kfmanager/ui/FilePanelTab.java +++ b/src/main/java/com/kfmanager/ui/FilePanelTab.java @@ -16,9 +16,17 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.List; - import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; +import java.io.InputStream; +import java.io.OutputStream; +import org.apache.commons.compress.archivers.tar.TarArchiveEntry; +import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; +import org.apache.commons.compress.archivers.sevenz.SevenZFile; +import org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry; +import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream; +import com.github.junrar.Archive; +import com.github.junrar.rarfile.FileHeader; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; @@ -871,40 +879,29 @@ public class FilePanelTab extends JPanel { private boolean isArchiveFile(File f) { if (f == null) return false; String n = f.getName().toLowerCase(); - return n.endsWith(".zip") || n.endsWith(".jar"); + return n.endsWith(".zip") || n.endsWith(".jar") || n.endsWith(".tar") || n.endsWith(".tar.gz") || n.endsWith(".tgz") || n.endsWith(".7z") || n.endsWith(".rar"); } private Path extractArchiveToTemp(File archive) { if (archive == null || !archive.isFile()) return null; + String name = archive.getName().toLowerCase(); try { Path tempDir = Files.createTempDirectory("kfmanager-archive-"); - try (ZipInputStream zis = new ZipInputStream(Files.newInputStream(archive.toPath()))) { - ZipEntry entry; - while ((entry = zis.getNextEntry()) != null) { - String entryName = entry.getName(); - // Normalize entry name and prevent zip-slip - Path resolved = tempDir.resolve(entryName).normalize(); - if (!resolved.startsWith(tempDir)) { - // suspicious entry, skip - zis.closeEntry(); - continue; - } - - if (entry.isDirectory() || entryName.endsWith("/")) { - Files.createDirectories(resolved); - } else { - Path parent = resolved.getParent(); - if (parent != null) Files.createDirectories(parent); - // Copy entry contents - Files.copy(zis, resolved, StandardCopyOption.REPLACE_EXISTING); - } - zis.closeEntry(); - } + if (name.endsWith(".zip") || name.endsWith(".jar")) { + extractZip(archive, tempDir); + } else if (name.endsWith(".tar.gz") || name.endsWith(".tgz")) { + extractTarGz(archive, tempDir); + } else if (name.endsWith(".tar")) { + extractTar(archive, tempDir); + } else if (name.endsWith(".7z")) { + extractSevenZ(archive, tempDir); + } else if (name.endsWith(".rar")) { + extractRar(archive, tempDir); } return tempDir; - } catch (IOException ex) { + } catch (Exception ex) { // extraction failed; attempt best-effort cleanup try { if (currentArchiveTempDir != null) deleteTempDirRecursively(currentArchiveTempDir); @@ -913,6 +910,116 @@ public class FilePanelTab extends JPanel { } } + private void extractZip(File archive, Path tempDir) throws IOException { + try (ZipInputStream zis = new ZipInputStream(Files.newInputStream(archive.toPath()))) { + ZipEntry entry; + while ((entry = zis.getNextEntry()) != null) { + String entryName = entry.getName(); + Path resolved = tempDir.resolve(entryName).normalize(); + if (!resolved.startsWith(tempDir)) { + zis.closeEntry(); + continue; + } + + if (entry.isDirectory() || entryName.endsWith("/")) { + Files.createDirectories(resolved); + } else { + Path parent = resolved.getParent(); + if (parent != null) Files.createDirectories(parent); + Files.copy(zis, resolved, StandardCopyOption.REPLACE_EXISTING); + } + zis.closeEntry(); + } + } + } + + private void extractSevenZ(File archive, Path tempDir) throws IOException { + try (SevenZFile sevenZFile = new SevenZFile(archive)) { + SevenZArchiveEntry entry; + while ((entry = sevenZFile.getNextEntry()) != null) { + String entryName = entry.getName(); + Path resolved = tempDir.resolve(entryName).normalize(); + if (!resolved.startsWith(tempDir)) { + continue; + } + + if (entry.isDirectory()) { + Files.createDirectories(resolved); + } else { + Path parent = resolved.getParent(); + if (parent != null) Files.createDirectories(parent); + + try (OutputStream os = Files.newOutputStream(resolved)) { + byte[] buffer = new byte[8192]; + int bytesRead; + while ((bytesRead = sevenZFile.read(buffer)) != -1) { + os.write(buffer, 0, bytesRead); + } + } + } + } + } + } + + private void extractRar(File archiveFile, Path tempDir) throws Exception { + try (Archive archive = new Archive(archiveFile)) { + FileHeader fh = archive.nextFileHeader(); + while (fh != null) { + String entryName = fh.getFileName().replace('\\', '/'); + Path resolved = tempDir.resolve(entryName).normalize(); + if (!resolved.startsWith(tempDir)) { + fh = archive.nextFileHeader(); + continue; + } + + if (fh.isDirectory()) { + Files.createDirectories(resolved); + } else { + Path parent = resolved.getParent(); + if (parent != null) Files.createDirectories(parent); + try (OutputStream os = Files.newOutputStream(resolved)) { + archive.extractFile(fh, os); + } + } + fh = archive.nextFileHeader(); + } + } + } + + private void extractTarGz(File archive, Path tempDir) throws IOException { + try (InputStream fis = Files.newInputStream(archive.toPath()); + InputStream gzis = new GzipCompressorInputStream(fis); + TarArchiveInputStream tais = new TarArchiveInputStream(gzis)) { + extractTarInternal(tais, tempDir); + } + } + + private void extractTar(File archive, Path tempDir) throws IOException { + try (InputStream fis = Files.newInputStream(archive.toPath()); + TarArchiveInputStream tais = new TarArchiveInputStream(fis)) { + extractTarInternal(tais, tempDir); + } + } + + private void extractTarInternal(TarArchiveInputStream tais, Path tempDir) throws IOException { + TarArchiveEntry entry; + while ((entry = tais.getNextTarEntry()) != null) { + String entryName = entry.getName(); + Path resolved = tempDir.resolve(entryName).normalize(); + if (!resolved.startsWith(tempDir)) { + continue; + } + + if (entry.isDirectory()) { + Files.createDirectories(resolved); + } else { + Path parent = resolved.getParent(); + if (parent != null) Files.createDirectories(parent); + Files.copy(tais, resolved, StandardCopyOption.REPLACE_EXISTING); + } + } + } + private void deleteTempDirRecursively(Path dir) { if (dir == null) return; try {