Skip to content
Permalink
Browse files
Sort members.
  • Loading branch information
garydgregory committed Feb 13, 2022
1 parent bbd9f34 commit 96a1c7552aa0b3819815e0beda9063068dbb9095
Showing 1 changed file with 139 additions and 139 deletions.
@@ -58,77 +58,82 @@ private interface EntryWriter {
}

/**
* Expands {@code archive} into {@code targetDirectory}.
*
* <p>Tries to auto-detect the archive's format.</p>
*
* @param archive the file to expand
* @param targetDirectory the target directory
* @throws IOException if an I/O error occurs
* @throws ArchiveException if the archive cannot be read for other reasons
* @param targetDirectory May be null to simulate output to dev/null on Linux and NUL on Windows.
*/
public void expand(final File archive, final File targetDirectory) throws IOException, ArchiveException {
expand(archive.toPath(), toPath(targetDirectory));
private void expand(final ArchiveEntrySupplier supplier, final EntryWriter writer, final Path targetDirectory)
throws IOException {
final boolean nullTarget = targetDirectory == null;
final Path targetDirPath = nullTarget ? null : targetDirectory.normalize();
ArchiveEntry nextEntry = supplier.getNextReadableEntry();
while (nextEntry != null) {
final Path targetPath = nullTarget ? null : targetDirectory.resolve(nextEntry.getName());
// check if targetDirectory and f are the same path - this may
// happen if the nextEntry.getName() is "./"
if (!nullTarget && !targetPath.normalize().startsWith(targetDirPath) && !Files.isSameFile(targetDirectory, targetPath)) {
throw new IOException("Expanding " + nextEntry.getName() + " would create file outside of " + targetDirectory);
}
if (nextEntry.isDirectory()) {
if (!nullTarget && !Files.isDirectory(targetPath) && Files.createDirectories(targetPath) == null) {
throw new IOException("Failed to create directory " + targetPath);
}
} else {
final Path parent = nullTarget ? null : targetPath.getParent();
if (!nullTarget && !Files.isDirectory(parent) && Files.createDirectories(parent) == null) {
throw new IOException("Failed to create directory " + parent);
}
if (nullTarget) {
writer.writeEntryDataTo(nextEntry, null);
} else {
try (OutputStream outputStream = Files.newOutputStream(targetPath)) {
writer.writeEntryDataTo(nextEntry, outputStream);
}
}
}
nextEntry = supplier.getNextReadableEntry();
}
}

/**
* Expands {@code archive} into {@code targetDirectory}.
*
* <p>Tries to auto-detect the archive's format.</p>
*
* @param archive the file to expand
* @param targetDirectory the target directory
* @param targetDirectory the target directory, may be null to simulate output to dev/null on Linux and NUL on Windows.
* @throws IOException if an I/O error occurs
* @throws ArchiveException if the archive cannot be read for other reasons
* @since 1.22
*/
public void expand(final Path archive, final Path targetDirectory) throws IOException, ArchiveException {
String format = null;
try (InputStream inputStream = new BufferedInputStream(Files.newInputStream(archive))) {
format = ArchiveStreamFactory.detect(inputStream);
}
expand(format, archive, targetDirectory);
public void expand(final ArchiveInputStream archive, final File targetDirectory) throws IOException {
expand(archive, toPath(targetDirectory));
}

/**
* Expands {@code archive} into {@code targetDirectory}.
*
* @param archive the file to expand
* @param targetDirectory the target directory
* @param format the archive format. This uses the same format as
* accepted by {@link ArchiveStreamFactory}.
* @param targetDirectory the target directory, may be null to simulate output to dev/null on Linux and NUL on Windows.
* @throws IOException if an I/O error occurs
* @throws ArchiveException if the archive cannot be read for other reasons
* @since 1.22
*/
public void expand(final String format, final File archive, final File targetDirectory) throws IOException, ArchiveException {
expand(format, archive.toPath(), toPath(targetDirectory));
}

private Path toPath(final File targetDirectory) {
return targetDirectory != null ? targetDirectory.toPath() : null;
public void expand(final ArchiveInputStream archive, final Path targetDirectory) throws IOException {
expand(() -> {
ArchiveEntry next = archive.getNextEntry();
while (next != null && !archive.canReadEntryData(next)) {
next = archive.getNextEntry();
}
return next;
}, (entry, out) -> IOUtils.copy(archive, out), targetDirectory);
}

/**
* Expands {@code archive} into {@code targetDirectory}.
*
* <p>Tries to auto-detect the archive's format.</p>
*
* @param archive the file to expand
* @param targetDirectory the target directory
* @param format the archive format. This uses the same format as
* accepted by {@link ArchiveStreamFactory}.
* @throws IOException if an I/O error occurs
* @throws ArchiveException if the archive cannot be read for other reasons
* @since 1.22
*/
public void expand(final String format, final Path archive, final Path targetDirectory) throws IOException, ArchiveException {
if (prefersSeekableByteChannel(format)) {
try (SeekableByteChannel channel = FileChannel.open(archive, StandardOpenOption.READ)) {
expand(format, channel, targetDirectory, CloseableConsumer.CLOSING_CONSUMER);
}
return;
}
try (InputStream inputStream = new BufferedInputStream(Files.newInputStream(archive))) {
expand(format, inputStream, targetDirectory, CloseableConsumer.CLOSING_CONSUMER);
}
public void expand(final File archive, final File targetDirectory) throws IOException, ArchiveException {
expand(archive.toPath(), toPath(targetDirectory));
}

/**
@@ -179,6 +184,71 @@ public void expand(final InputStream archive, final File targetDirectory, final
}
}

/**
* Expands {@code archive} into {@code targetDirectory}.
*
* <p>Tries to auto-detect the archive's format.</p>
*
* @param archive the file to expand
* @param targetDirectory the target directory
* @throws IOException if an I/O error occurs
* @throws ArchiveException if the archive cannot be read for other reasons
* @since 1.22
*/
public void expand(final Path archive, final Path targetDirectory) throws IOException, ArchiveException {
String format = null;
try (InputStream inputStream = new BufferedInputStream(Files.newInputStream(archive))) {
format = ArchiveStreamFactory.detect(inputStream);
}
expand(format, archive, targetDirectory);
}

/**
* Expands {@code archive} into {@code targetDirectory}.
*
* @param archive the file to expand
* @param targetDirectory the target directory, may be null to simulate output to dev/null on Linux and NUL on Windows.
* @throws IOException if an I/O error occurs
*/
public void expand(final SevenZFile archive, final File targetDirectory) throws IOException {
expand(archive, toPath(targetDirectory));
}

/**
* Expands {@code archive} into {@code targetDirectory}.
*
* @param archive the file to expand
* @param targetDirectory the target directory, may be null to simulate output to dev/null on Linux and NUL on Windows.
* @throws IOException if an I/O error occurs
* @since 1.22
*/
public void expand(final SevenZFile archive, final Path targetDirectory)
throws IOException {
expand(archive::getNextEntry, (entry, out) -> {
final byte[] buffer = new byte[8192];
int n;
while (-1 != (n = archive.read(buffer))) {
if (out != null) {
out.write(buffer, 0, n);
}
}
}, targetDirectory);
}

/**
* Expands {@code archive} into {@code targetDirectory}.
*
* @param archive the file to expand
* @param targetDirectory the target directory
* @param format the archive format. This uses the same format as
* accepted by {@link ArchiveStreamFactory}.
* @throws IOException if an I/O error occurs
* @throws ArchiveException if the archive cannot be read for other reasons
*/
public void expand(final String format, final File archive, final File targetDirectory) throws IOException, ArchiveException {
expand(format, archive.toPath(), toPath(targetDirectory));
}

/**
* Expands {@code archive} into {@code targetDirectory}.
*
@@ -252,6 +322,29 @@ public void expand(final String format, final InputStream archive, final Path ta
}
}

/**
* Expands {@code archive} into {@code targetDirectory}.
*
* @param archive the file to expand
* @param targetDirectory the target directory
* @param format the archive format. This uses the same format as
* accepted by {@link ArchiveStreamFactory}.
* @throws IOException if an I/O error occurs
* @throws ArchiveException if the archive cannot be read for other reasons
* @since 1.22
*/
public void expand(final String format, final Path archive, final Path targetDirectory) throws IOException, ArchiveException {
if (prefersSeekableByteChannel(format)) {
try (SeekableByteChannel channel = FileChannel.open(archive, StandardOpenOption.READ)) {
expand(format, channel, targetDirectory, CloseableConsumer.CLOSING_CONSUMER);
}
return;
}
try (InputStream inputStream = new BufferedInputStream(Files.newInputStream(archive))) {
expand(format, inputStream, targetDirectory, CloseableConsumer.CLOSING_CONSUMER);
}
}

/**
* Expands {@code archive} into {@code targetDirectory}.
*
@@ -336,35 +429,6 @@ public void expand(final String format, final SeekableByteChannel archive, final
}
}

/**
* Expands {@code archive} into {@code targetDirectory}.
*
* @param archive the file to expand
* @param targetDirectory the target directory, may be null to simulate output to dev/null on Linux and NUL on Windows.
* @throws IOException if an I/O error occurs
*/
public void expand(final ArchiveInputStream archive, final File targetDirectory) throws IOException {
expand(archive, toPath(targetDirectory));
}

/**
* Expands {@code archive} into {@code targetDirectory}.
*
* @param archive the file to expand
* @param targetDirectory the target directory, may be null to simulate output to dev/null on Linux and NUL on Windows.
* @throws IOException if an I/O error occurs
* @since 1.22
*/
public void expand(final ArchiveInputStream archive, final Path targetDirectory) throws IOException {
expand(() -> {
ArchiveEntry next = archive.getNextEntry();
while (next != null && !archive.canReadEntryData(next)) {
next = archive.getNextEntry();
}
return next;
}, (entry, out) -> IOUtils.copy(archive, out), targetDirectory);
}

/**
* Expands {@code archive} into {@code targetDirectory}.
*
@@ -431,78 +495,14 @@ public void expand(final ZipFile archive, final Path targetDirectory)
}, targetDirectory);
}

/**
* Expands {@code archive} into {@code targetDirectory}.
*
* @param archive the file to expand
* @param targetDirectory the target directory, may be null to simulate output to dev/null on Linux and NUL on Windows.
* @throws IOException if an I/O error occurs
*/
public void expand(final SevenZFile archive, final File targetDirectory) throws IOException {
expand(archive, toPath(targetDirectory));
}

/**
* Expands {@code archive} into {@code targetDirectory}.
*
* @param archive the file to expand
* @param targetDirectory the target directory, may be null to simulate output to dev/null on Linux and NUL on Windows.
* @throws IOException if an I/O error occurs
* @since 1.22
*/
public void expand(final SevenZFile archive, final Path targetDirectory)
throws IOException {
expand(archive::getNextEntry, (entry, out) -> {
final byte[] buffer = new byte[8192];
int n;
while (-1 != (n = archive.read(buffer))) {
if (out != null) {
out.write(buffer, 0, n);
}
}
}, targetDirectory);
}

private boolean prefersSeekableByteChannel(final String format) {
return ArchiveStreamFactory.TAR.equalsIgnoreCase(format)
|| ArchiveStreamFactory.ZIP.equalsIgnoreCase(format)
|| ArchiveStreamFactory.SEVEN_Z.equalsIgnoreCase(format);
}

/**
* @param targetDirectory May be null to simulate output to dev/null on Linux and NUL on Windows.
*/
private void expand(final ArchiveEntrySupplier supplier, final EntryWriter writer, final Path targetDirectory)
throws IOException {
final boolean nullTarget = targetDirectory == null;
final Path targetDirPath = nullTarget ? null : targetDirectory.normalize();
ArchiveEntry nextEntry = supplier.getNextReadableEntry();
while (nextEntry != null) {
final Path targetPath = nullTarget ? null : targetDirectory.resolve(nextEntry.getName());
// check if targetDirectory and f are the same path - this may
// happen if the nextEntry.getName() is "./"
if (!nullTarget && !targetPath.normalize().startsWith(targetDirPath) && !Files.isSameFile(targetDirectory, targetPath)) {
throw new IOException("Expanding " + nextEntry.getName() + " would create file outside of " + targetDirectory);
}
if (nextEntry.isDirectory()) {
if (!nullTarget && !Files.isDirectory(targetPath) && Files.createDirectories(targetPath) == null) {
throw new IOException("Failed to create directory " + targetPath);
}
} else {
final Path parent = nullTarget ? null : targetPath.getParent();
if (!nullTarget && !Files.isDirectory(parent) && Files.createDirectories(parent) == null) {
throw new IOException("Failed to create directory " + parent);
}
if (nullTarget) {
writer.writeEntryDataTo(nextEntry, null);
} else {
try (OutputStream outputStream = Files.newOutputStream(targetPath)) {
writer.writeEntryDataTo(nextEntry, outputStream);
}
}
}
nextEntry = supplier.getNextReadableEntry();
}
private Path toPath(final File targetDirectory) {
return targetDirectory != null ? targetDirectory.toPath() : null;
}

}

0 comments on commit 96a1c75

Please sign in to comment.