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 {