From 9ee32eafc12436b625c020ac96cd2a4e091af972 Mon Sep 17 00:00:00 2001 From: Gauthier Roebroeck Date: Mon, 27 Jul 2020 11:39:04 +0800 Subject: [PATCH] feat: multi-part extraction from inputstream closes #52 --- src/main/java/com/github/junrar/Archive.java | 2 +- src/main/java/com/github/junrar/Junrar.java | 26 +++++++++++++++ .../com/github/junrar/unpack/ComprDataIO.java | 2 +- .../junrar/volume/FileVolumeManager.java | 2 +- .../junrar/volume/InputStreamVolume.java | 7 +++- .../volume/InputStreamVolumeManager.java | 23 ++++++++++--- .../github/junrar/volume/VolumeManager.java | 10 +++++- .../github/junrar/VolumeExtractorTest.java | 33 +++++++++++++++++++ 8 files changed, 96 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/github/junrar/Archive.java b/src/main/java/com/github/junrar/Archive.java index a9e077f42..26727d41c 100644 --- a/src/main/java/com/github/junrar/Archive.java +++ b/src/main/java/com/github/junrar/Archive.java @@ -121,7 +121,7 @@ public Archive( this.password = password; try { - setVolume(this.volumeManager.nextArchive(this, null)); + setVolume(this.volumeManager.nextVolume(this, null)); } catch (IOException | RarException e) { try { close(); diff --git a/src/main/java/com/github/junrar/Junrar.java b/src/main/java/com/github/junrar/Junrar.java index 8706a212e..2b079283b 100644 --- a/src/main/java/com/github/junrar/Junrar.java +++ b/src/main/java/com/github/junrar/Junrar.java @@ -2,6 +2,7 @@ import com.github.junrar.exception.RarException; import com.github.junrar.rarfile.FileHeader; +import com.github.junrar.volume.VolumeManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -52,6 +53,22 @@ public static List extract(final InputStream resourceAsStream, final File return extractArchiveTo(arch, lfe); } + public static List extract(final VolumeManager volumeManager, final File destinationFolder) throws IOException, RarException { + validateDestinationPath(destinationFolder); + + final Archive arch = createArchiveOrThrowException(volumeManager, null); + LocalFolderExtractor lfe = new LocalFolderExtractor(destinationFolder); + return extractArchiveTo(arch, lfe); + } + + public static List extract(final VolumeManager volumeManager, final File destinationFolder, final String password) throws IOException, RarException { + validateDestinationPath(destinationFolder); + + final Archive arch = createArchiveOrThrowException(volumeManager, password); + LocalFolderExtractor lfe = new LocalFolderExtractor(destinationFolder); + return extractArchiveTo(arch, lfe); + } + public static List getContentsDescription(final File rar) throws RarException, IOException { validateRarPath(rar); @@ -73,6 +90,15 @@ public static List getContentsDescription(final File rar) th return contents; } + private static Archive createArchiveOrThrowException(final VolumeManager volumeManager, final String password) throws RarException, IOException { + try { + return new Archive(volumeManager, null, password); + } catch (final RarException | IOException e) { + Junrar.logger.error("Error while creating archive", e); + throw e; + } + } + private static Archive createArchiveOrThrowException(final InputStream rarAsStream, final String password) throws RarException, IOException { try { return new Archive(rarAsStream, password); diff --git a/src/main/java/com/github/junrar/unpack/ComprDataIO.java b/src/main/java/com/github/junrar/unpack/ComprDataIO.java index 514752800..420d4ff60 100644 --- a/src/main/java/com/github/junrar/unpack/ComprDataIO.java +++ b/src/main/java/com/github/junrar/unpack/ComprDataIO.java @@ -139,7 +139,7 @@ public int unpRead(byte[] addr, int offset, int count) throws IOException, RarEx archive.bytesReadRead(retCode); if (unpPackedSize == 0 && subHead.isSplitAfter()) { - Volume nextVolume = archive.getVolumeManager().nextArchive(archive, archive.getVolume()); + Volume nextVolume = archive.getVolumeManager().nextVolume(archive, archive.getVolume()); if (nextVolume == null) { nextVolumeMissing = true; return -1; diff --git a/src/main/java/com/github/junrar/volume/FileVolumeManager.java b/src/main/java/com/github/junrar/volume/FileVolumeManager.java index f90f93fdb..b02b48f30 100644 --- a/src/main/java/com/github/junrar/volume/FileVolumeManager.java +++ b/src/main/java/com/github/junrar/volume/FileVolumeManager.java @@ -16,7 +16,7 @@ public FileVolumeManager(final File firstVolume) { } @Override - public Volume nextArchive(final Archive archive, final Volume last) { + public Volume nextVolume(final Archive archive, final Volume last) { if (last == null) return new FileVolume(archive, this.firstVolume); final FileVolume lastFileVolume = (FileVolume) last; diff --git a/src/main/java/com/github/junrar/volume/InputStreamVolume.java b/src/main/java/com/github/junrar/volume/InputStreamVolume.java index c67bd2b43..09c4940b4 100644 --- a/src/main/java/com/github/junrar/volume/InputStreamVolume.java +++ b/src/main/java/com/github/junrar/volume/InputStreamVolume.java @@ -10,10 +10,12 @@ public class InputStreamVolume implements Volume { private final Archive archive; private final InputStream inputStream; + private final int position; - public InputStreamVolume(final Archive archive, final InputStream inputStream) { + public InputStreamVolume(final Archive archive, final InputStream inputStream, final int position) { this.archive = archive; this.inputStream = inputStream; + this.position = position; } @Override @@ -31,4 +33,7 @@ public Archive getArchive() { return this.archive; } + public int getPosition() { + return position; + } } diff --git a/src/main/java/com/github/junrar/volume/InputStreamVolumeManager.java b/src/main/java/com/github/junrar/volume/InputStreamVolumeManager.java index 8756d03bb..226a2f6fa 100644 --- a/src/main/java/com/github/junrar/volume/InputStreamVolumeManager.java +++ b/src/main/java/com/github/junrar/volume/InputStreamVolumeManager.java @@ -3,18 +3,33 @@ import com.github.junrar.Archive; import java.io.InputStream; +import java.util.HashMap; +import java.util.List; +import java.util.Map; public class InputStreamVolumeManager implements VolumeManager { - private final InputStream is; + private final Map streams = new HashMap<>(); public InputStreamVolumeManager(final InputStream is) { - this.is = is; + streams.put(1, is); + } + + public InputStreamVolumeManager(List streams) { + for (int i = 0; i < streams.size(); i++) { + this.streams.put(i + 1, streams.get(i)); + } } @Override - public Volume nextArchive(final Archive archive, final Volume lastVolume) { - return new InputStreamVolume(archive, this.is); + public Volume nextVolume(final Archive archive, final Volume lastVolume) { + if (lastVolume == null) return new InputStreamVolume(archive, streams.get(1), 1); + + InputStreamVolume lastStreamVolume = (InputStreamVolume) lastVolume; + int nextPosition = lastStreamVolume.getPosition() + 1; + InputStream next = streams.get(nextPosition); + if (next != null) return new InputStreamVolume(archive, next, nextPosition); + return null; } } diff --git a/src/main/java/com/github/junrar/volume/VolumeManager.java b/src/main/java/com/github/junrar/volume/VolumeManager.java index f252db6ee..df1cd0a19 100644 --- a/src/main/java/com/github/junrar/volume/VolumeManager.java +++ b/src/main/java/com/github/junrar/volume/VolumeManager.java @@ -8,5 +8,13 @@ * @author Rogiel */ public interface VolumeManager { - Volume nextArchive(Archive archive, Volume lastVolume) throws IOException; + /** + * Returns either the first volume or the next volume. + * + * @param archive the archive the volumes are part of + * @param lastVolume the last volume before the one to return + * @return the first volume if lastVolume is null, else the next volume after lastVolume + * @throws IOException if the volume cannot be read + */ + Volume nextVolume(Archive archive, Volume lastVolume) throws IOException; } diff --git a/src/test/java/com/github/junrar/VolumeExtractorTest.java b/src/test/java/com/github/junrar/VolumeExtractorTest.java index ca0b61f65..4ab41bbd1 100644 --- a/src/test/java/com/github/junrar/VolumeExtractorTest.java +++ b/src/test/java/com/github/junrar/VolumeExtractorTest.java @@ -1,6 +1,7 @@ package com.github.junrar; import com.github.junrar.exception.RarException; +import com.github.junrar.volume.InputStreamVolumeManager; import org.apache.commons.io.FileUtils; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -9,9 +10,15 @@ import org.junit.jupiter.params.provider.MethodSource; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import java.util.stream.Stream; import static org.assertj.core.api.Assertions.assertThat; @@ -45,6 +52,32 @@ public void extractionFromVolumedFile(String ressourceDir, String firstVolume) t checkContent(unpackedDir); } + @ParameterizedTest + @MethodSource("volumeArgs") + public void extractionFromVolumedStream(String ressourceDir, String firstVolume) throws Exception { + File dir = new File(getClass().getResource(ressourceDir).getPath()); + TestCommons.copyRarsToFolder(tempFolder, dir); + + List files = Arrays.stream(tempFolder.listFiles()) + .filter(File::isFile) + .sorted() + .collect(Collectors.toList()); + System.out.println(files); + + List streams = new ArrayList<>(); + for (File f : files) { + streams.add(new FileInputStream(f)); + } + + final File unpackedDir = new File(tempFolder, "test-documents"); + unpackedDir.delete(); + unpackedDir.mkdir(); + + Junrar.extract(new InputStreamVolumeManager(streams), unpackedDir); + + checkContent(unpackedDir); + } + private static Stream volumeArgs() { return Stream.of( Arguments.of("volumes/new-numbers", "test-documents.000.rar"),