added sup[port for more archivers

This commit is contained in:
Radek Davidek 2026-01-16 18:30:28 +01:00
parent ae7cf32132
commit 0a95ad9f53
2 changed files with 162 additions and 25 deletions

30
pom.xml
View File

@ -21,6 +21,23 @@
<build> <build>
<plugins> <plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.9.0</version>
<executions>
<execution>
<phase>install</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<includeScope>runtime</includeScope>
</configuration>
</execution>
</executions>
</plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
@ -68,4 +85,17 @@
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>1.21</version>
</dependency>
<dependency>
<groupId>com.github.junrar</groupId>
<artifactId>junrar</artifactId>
<version>7.4.1</version>
</dependency>
</dependencies>
</project> </project>

View File

@ -16,9 +16,17 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream; 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.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.StandardCopyOption; import java.nio.file.StandardCopyOption;
@ -871,22 +879,44 @@ public class FilePanelTab extends JPanel {
private boolean isArchiveFile(File f) { private boolean isArchiveFile(File f) {
if (f == null) return false; if (f == null) return false;
String n = f.getName().toLowerCase(); 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) { private Path extractArchiveToTemp(File archive) {
if (archive == null || !archive.isFile()) return null; if (archive == null || !archive.isFile()) return null;
String name = archive.getName().toLowerCase();
try { try {
Path tempDir = Files.createTempDirectory("kfmanager-archive-"); Path tempDir = Files.createTempDirectory("kfmanager-archive-");
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 (Exception ex) {
// extraction failed; attempt best-effort cleanup
try {
if (currentArchiveTempDir != null) deleteTempDirRecursively(currentArchiveTempDir);
} catch (Exception ignore) {}
return null;
}
}
private void extractZip(File archive, Path tempDir) throws IOException {
try (ZipInputStream zis = new ZipInputStream(Files.newInputStream(archive.toPath()))) { try (ZipInputStream zis = new ZipInputStream(Files.newInputStream(archive.toPath()))) {
ZipEntry entry; ZipEntry entry;
while ((entry = zis.getNextEntry()) != null) { while ((entry = zis.getNextEntry()) != null) {
String entryName = entry.getName(); String entryName = entry.getName();
// Normalize entry name and prevent zip-slip
Path resolved = tempDir.resolve(entryName).normalize(); Path resolved = tempDir.resolve(entryName).normalize();
if (!resolved.startsWith(tempDir)) { if (!resolved.startsWith(tempDir)) {
// suspicious entry, skip
zis.closeEntry(); zis.closeEntry();
continue; continue;
} }
@ -896,20 +926,97 @@ public class FilePanelTab extends JPanel {
} else { } else {
Path parent = resolved.getParent(); Path parent = resolved.getParent();
if (parent != null) Files.createDirectories(parent); if (parent != null) Files.createDirectories(parent);
// Copy entry contents
Files.copy(zis, resolved, StandardCopyOption.REPLACE_EXISTING); Files.copy(zis, resolved, StandardCopyOption.REPLACE_EXISTING);
} }
zis.closeEntry(); zis.closeEntry();
} }
} }
}
return tempDir; private void extractSevenZ(File archive, Path tempDir) throws IOException {
} catch (IOException ex) { try (SevenZFile sevenZFile = new SevenZFile(archive)) {
// extraction failed; attempt best-effort cleanup SevenZArchiveEntry entry;
try { while ((entry = sevenZFile.getNextEntry()) != null) {
if (currentArchiveTempDir != null) deleteTempDirRecursively(currentArchiveTempDir); String entryName = entry.getName();
} catch (Exception ignore) {} Path resolved = tempDir.resolve(entryName).normalize();
return null; 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);
}
} }
} }