You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by bo...@apache.org on 2018/04/30 04:32:59 UTC
[1/2] commons-compress git commit: COMPRESS-118 add archuve expansion
API
Repository: commons-compress
Updated Branches:
refs/heads/master 44980ffc7 -> 75a7edc74
COMPRESS-118 add archuve expansion API
Project: http://git-wip-us.apache.org/repos/asf/commons-compress/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-compress/commit/33558253
Tree: http://git-wip-us.apache.org/repos/asf/commons-compress/tree/33558253
Diff: http://git-wip-us.apache.org/repos/asf/commons-compress/diff/33558253
Branch: refs/heads/master
Commit: 335582530a7f0dbb137e42655716962abae3addf
Parents: 44980ff
Author: Stefan Bodewig <bo...@apache.org>
Authored: Mon Apr 30 06:23:59 2018 +0200
Committer: Stefan Bodewig <bo...@apache.org>
Committed: Mon Apr 30 06:23:59 2018 +0200
----------------------------------------------------------------------
.../compress/archivers/examples/Archive.java | 19 +--
.../archivers/examples/ArchiveEntrySource.java | 34 +++++
.../archivers/examples/ArchiveSources.java | 112 +++++++++++++++++
.../archivers/examples/ChainDefinition.java | 8 +-
.../archivers/examples/ChainRunner.java | 46 +++++++
.../archivers/examples/DirectorySink.java | 69 +++++++++++
.../compress/archivers/examples/Expand.java | 110 ++++++++++++++++
.../compress/archivers/examples/ExpandCli.java | 48 +++++++
.../examples/SevenZArchiveEntrySource.java | 124 +++++++++++++++++++
.../examples/StreamBasedArchiveEntrySource.java | 97 +++++++++++++++
.../examples/ZipArchiveEntrySource.java | 96 ++++++++++++++
.../compress/utils/NoCloseInputStream.java | 43 +++++++
12 files changed, 784 insertions(+), 22 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/33558253/src/main/java/org/apache/commons/compress/archivers/examples/Archive.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/compress/archivers/examples/Archive.java b/src/main/java/org/apache/commons/compress/archivers/examples/Archive.java
index a929442..8b5a5d2 100644
--- a/src/main/java/org/apache/commons/compress/archivers/examples/Archive.java
+++ b/src/main/java/org/apache/commons/compress/archivers/examples/Archive.java
@@ -124,25 +124,8 @@ public class Archive {
public void to(Sink<File> sink) throws IOException, ArchiveException {
chainDef.add(sink);
chainDef.freeze();
- new Archive(source, chainDef, sink).run();
+ new ChainRunner<File>(source, chainDef, sink).run();
}
}
- private final Source<File> source;
- private final ChainDefinition<File> chainDef;
- private final Sink<File> sink;
-
- private Archive(Source<File> source, ChainDefinition<File> chainDef, Sink<File> sink) {
- this.source = source;
- this.chainDef = chainDef;
- this.sink = sink;
- }
-
- private void run() throws IOException, ArchiveException {
- ThrowingIterator<ChainPayload<File>> iter = source.get();
- while (iter.hasNext()) {
- chainDef.chain().next(iter.next());
- }
- sink.finish();
- }
}
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/33558253/src/main/java/org/apache/commons/compress/archivers/examples/ArchiveEntrySource.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/compress/archivers/examples/ArchiveEntrySource.java b/src/main/java/org/apache/commons/compress/archivers/examples/ArchiveEntrySource.java
new file mode 100644
index 0000000..f114eb6
--- /dev/null
+++ b/src/main/java/org/apache/commons/compress/archivers/examples/ArchiveEntrySource.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.compress.archivers.examples;
+
+import org.apache.commons.compress.archivers.ArchiveEntry;
+
+/**
+ * Combines Source and a factory for filter that skips unreadable entries.
+ * @since 1.17
+ */
+public interface ArchiveEntrySource extends Source<ArchiveEntry> {
+
+ /**
+ * Provides a filter that can be used to skip entries the
+ * underlying source is unable to read the content of.
+ */
+ Filter<ArchiveEntry> skipUnreadable();
+}
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/33558253/src/main/java/org/apache/commons/compress/archivers/examples/ArchiveSources.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/compress/archivers/examples/ArchiveSources.java b/src/main/java/org/apache/commons/compress/archivers/examples/ArchiveSources.java
new file mode 100644
index 0000000..39ca236
--- /dev/null
+++ b/src/main/java/org/apache/commons/compress/archivers/examples/ArchiveSources.java
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.compress.archivers.examples;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.FileInputStream;
+import java.nio.channels.Channels;
+import java.nio.channels.FileChannel;
+import java.nio.channels.SeekableByteChannel;
+import java.nio.file.StandardOpenOption;
+import org.apache.commons.compress.archivers.ArchiveException;
+import org.apache.commons.compress.archivers.ArchiveInputStream;
+import org.apache.commons.compress.archivers.ArchiveStreamFactory;
+import org.apache.commons.compress.archivers.sevenz.SevenZFile;
+import org.apache.commons.compress.archivers.zip.ZipFile;
+
+/**
+ * Supplies factory methods for ArchiveEntry sources that read from archives,
+ * @since 1.17
+ */
+public class ArchiveSources {
+ /**
+ * Builder for {@link ArchiveEntrySource} that needs to know its format.
+ * @since 1.17
+ */
+ public interface PendingFormat {
+ ArchiveEntrySource detectFormat() throws IOException, ArchiveException;
+ ArchiveEntrySource withFormat(String format) throws IOException, ArchiveException;
+ }
+
+ /**
+ * Uses {@link ArchiveFactory#createArchiveInputStream} unless special handling for ZIP or /z is required.
+ */
+ public static PendingFormat forFile(final File f) {
+ return new PendingFormat() {
+ @Override
+ public ArchiveEntrySource detectFormat() throws IOException, ArchiveException {
+ String format = null;
+ try (InputStream i = new BufferedInputStream(new FileInputStream(f))) {
+ format = new ArchiveStreamFactory().detect(i);
+ }
+ return withFormat(format);
+ }
+ @Override
+ public ArchiveEntrySource withFormat(String format) throws IOException, ArchiveException {
+ if (prefersSeekableByteChannel(format)) {
+ return forChannel(format, FileChannel.open(f.toPath(), StandardOpenOption.READ));
+ }
+ return new StreamBasedArchiveEntrySource(new ArchiveStreamFactory()
+ .createArchiveInputStream(format, new BufferedInputStream(new FileInputStream(f))));
+ }
+ };
+ }
+
+ /**
+ * Uses {@link ArchiveFactory#createArchiveInputStream} unless special handling for ZIP or /z is required.
+ */
+ public static ArchiveEntrySource forChannel(String format, SeekableByteChannel c)
+ throws IOException, ArchiveException {
+ if (!prefersSeekableByteChannel(format)) {
+ return new StreamBasedArchiveEntrySource(new ArchiveStreamFactory()
+ .createArchiveInputStream(format, Channels.newInputStream(c)));
+ } else if (ArchiveStreamFactory.ZIP.equalsIgnoreCase(format)) {
+ return new ZipArchiveEntrySource(c);
+ } else if (ArchiveStreamFactory.SEVEN_Z.equalsIgnoreCase(format)) {
+ return new SevenZArchiveEntrySource(c);
+ }
+ throw new ArchiveException("don't know how to handle format " + format);
+ }
+
+ /**
+ * Uses {@link ArchiveFactory#createArchiveInputStream}.
+ *
+ * <p>Will not support 7z.</p>
+ */
+ public static PendingFormat forStream(final InputStream in) {
+ return new PendingFormat() {
+ @Override
+ public ArchiveEntrySource detectFormat() throws IOException, ArchiveException {
+ return new StreamBasedArchiveEntrySource(new ArchiveStreamFactory().createArchiveInputStream(in));
+ }
+ @Override
+ public ArchiveEntrySource withFormat(String format) throws IOException, ArchiveException {
+ return new StreamBasedArchiveEntrySource(new ArchiveStreamFactory()
+ .createArchiveInputStream(format, in));
+ }
+ };
+ }
+
+ private static boolean prefersSeekableByteChannel(String format) {
+ return ArchiveStreamFactory.ZIP.equalsIgnoreCase(format) || ArchiveStreamFactory.SEVEN_Z.equalsIgnoreCase(format);
+ }
+}
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/33558253/src/main/java/org/apache/commons/compress/archivers/examples/ChainDefinition.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/compress/archivers/examples/ChainDefinition.java b/src/main/java/org/apache/commons/compress/archivers/examples/ChainDefinition.java
index 5136b1d..d8a387f 100644
--- a/src/main/java/org/apache/commons/compress/archivers/examples/ChainDefinition.java
+++ b/src/main/java/org/apache/commons/compress/archivers/examples/ChainDefinition.java
@@ -25,7 +25,7 @@ import java.util.LinkedList;
* The recipe for building a {@link Chain}.
* @since 1.17
*/
-public class ChainDefinition<T> {
+class ChainDefinition<T> {
private final Deque<ChainStep<T>> steps = new LinkedList<>();
private volatile boolean frozen = false;
@@ -33,7 +33,7 @@ public class ChainDefinition<T> {
* Adds a step.
* @throws IllegalStateException if the definition is already frozen.
*/
- public void add(ChainStep<T> step) {
+ void add(ChainStep<T> step) {
if (frozen) {
throw new IllegalStateException("the definition is already frozen");
}
@@ -47,7 +47,7 @@ public class ChainDefinition<T> {
*
* @throws IllegalStateException if the last step of the definition is not a sink.
*/
- public void freeze() {
+ void freeze() {
if (!frozen) {
frozen = true;
if (!(steps.getLast() instanceof Sink)) {
@@ -61,7 +61,7 @@ public class ChainDefinition<T> {
*
* @throws IllegalStateException if the definition is not frozen.
*/
- public Chain<T> chain() {
+ Chain<T> chain() {
if (!frozen) {
throw new IllegalStateException("the definition hasn't been frozen, yet");
}
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/33558253/src/main/java/org/apache/commons/compress/archivers/examples/ChainRunner.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/compress/archivers/examples/ChainRunner.java b/src/main/java/org/apache/commons/compress/archivers/examples/ChainRunner.java
new file mode 100644
index 0000000..5f43589
--- /dev/null
+++ b/src/main/java/org/apache/commons/compress/archivers/examples/ChainRunner.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.compress.archivers.examples;
+
+import java.io.IOException;
+import org.apache.commons.compress.archivers.ArchiveException;
+
+/**
+ * Contains the execution logic of a full chain including a source.
+ * @since 1.17
+ */
+class ChainRunner<T> {
+ private final Source<T> source;
+ private final ChainDefinition<T> chainDef;
+ private final Sink<T> sink;
+
+ ChainRunner(Source<T> source, ChainDefinition<T> chainDef, Sink<T> sink) {
+ this.source = source;
+ this.chainDef = chainDef;
+ this.sink = sink;
+ }
+
+ void run() throws IOException, ArchiveException {
+ ThrowingIterator<ChainPayload<T>> iter = source.get();
+ while (iter.hasNext()) {
+ chainDef.chain().next(iter.next());
+ }
+ sink.finish();
+ }
+}
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/33558253/src/main/java/org/apache/commons/compress/archivers/examples/DirectorySink.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/compress/archivers/examples/DirectorySink.java b/src/main/java/org/apache/commons/compress/archivers/examples/DirectorySink.java
new file mode 100644
index 0000000..9cc1597
--- /dev/null
+++ b/src/main/java/org/apache/commons/compress/archivers/examples/DirectorySink.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.compress.archivers.examples;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import org.apache.commons.compress.archivers.ArchiveEntry;
+import org.apache.commons.compress.archivers.ArchiveException;
+import org.apache.commons.compress.utils.IOUtils;
+
+/**
+ * A sink that expands archive entries into a directory.
+ * @since 1.17
+ */
+public class DirectorySink extends Sink<ArchiveEntry> {
+ private final File dir;
+ private final String dirPath;
+
+ /**
+ * @param dir the directory to provide entries from.
+ */
+ public DirectorySink(File dir) throws IOException {
+ if (!dir.isDirectory()) {
+ throw new IllegalArgumentException("dir is not a readable directory");
+ }
+ this.dir = dir;
+ dirPath = dir.getCanonicalPath();
+ }
+
+ @Override
+ public void consume(ChainPayload<ArchiveEntry> payload) throws IOException, ArchiveException {
+ File f = new File(dir, payload.getEntryName());
+ if (!f.getCanonicalPath().startsWith(dirPath)) {
+ throw new IOException("expanding " + payload.getEntryName() + " would create file outside of " + dir);
+ }
+ if (payload.getEntry().isDirectory()) {
+ f.mkdirs();
+ } else {
+ f.getParentFile().mkdirs();
+ try (OutputStream o = new FileOutputStream(f);
+ InputStream i = payload.getInput().get()) {
+ IOUtils.copy(i, o);
+ }
+ }
+ }
+
+ @Override
+ public void close() {
+ }
+}
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/33558253/src/main/java/org/apache/commons/compress/archivers/examples/Expand.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/compress/archivers/examples/Expand.java b/src/main/java/org/apache/commons/compress/archivers/examples/Expand.java
new file mode 100644
index 0000000..99e1f34
--- /dev/null
+++ b/src/main/java/org/apache/commons/compress/archivers/examples/Expand.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.compress.archivers.examples;
+
+import java.io.IOException;
+import org.apache.commons.compress.archivers.ArchiveEntry;
+import org.apache.commons.compress.archivers.ArchiveException;
+
+/**
+ * Consumes archive entries and passes them to a sink, usually used to
+ * expand an archive.
+ * @since 1.17
+ */
+public class Expand {
+ /**
+ * Sets up a chain of operations and consumes the entries from a source of archive entries.
+ * @since 1.17
+ */
+ public interface ChainBuilder {
+ /**
+ * Adds a filter to the chain.
+ */
+ ChainBuilder filter(Filter<ArchiveEntry> filter);
+ /**
+ * Adds a filter to the chain that filters out entries that cannot be read.
+ */
+ ChainBuilder skipUnreadable();
+ /**
+ * Adds a filter to the chain that suppresses all directory entries.
+ */
+ ChainBuilder skipDirectories();
+ /**
+ * Adds a transformer to the chain.
+ */
+ ChainBuilder map(Transformer<ArchiveEntry> transformer);
+ /**
+ * Adds a generic step to the chain.
+ */
+ ChainBuilder withStep(ChainStep<ArchiveEntry> step);
+ /**
+ * Actually consumes all the entries supplied.
+ */
+ void to(Sink<ArchiveEntry> sink) throws IOException, ArchiveException;
+ }
+
+ /**
+ * Sets the source of entries to process.
+ */
+ public static ChainBuilder source(ArchiveEntrySource source) {
+ return new Builder(source);
+ }
+
+ private static class Builder implements ChainBuilder {
+ private final ArchiveEntrySource source;
+ private ChainDefinition<ArchiveEntry> chainDef = new ChainDefinition<>();
+
+ Builder(ArchiveEntrySource source) {
+ this.source = source;
+ }
+
+ @Override
+ public ChainBuilder filter(Filter<ArchiveEntry> filter) {
+ return withStep(filter);
+ }
+ @Override
+ public ChainBuilder skipUnreadable() {
+ return filter(source.skipUnreadable());
+ }
+ @Override
+ public ChainBuilder skipDirectories() {
+ return filter(new Filter<ArchiveEntry>() {
+ @Override
+ public boolean accept(String entryName, ArchiveEntry e) {
+ return !e.isDirectory();
+ }
+ });
+ }
+ @Override
+ public ChainBuilder map(Transformer<ArchiveEntry> transformer) {
+ return withStep(transformer);
+ }
+ @Override
+ public ChainBuilder withStep(ChainStep<ArchiveEntry> step) {
+ chainDef.add(step);
+ return this;
+ }
+ @Override
+ public void to(Sink<ArchiveEntry> sink) throws IOException, ArchiveException {
+ chainDef.add(sink);
+ chainDef.freeze();
+ new ChainRunner<ArchiveEntry>(source, chainDef, sink).run();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/33558253/src/main/java/org/apache/commons/compress/archivers/examples/ExpandCli.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/compress/archivers/examples/ExpandCli.java b/src/main/java/org/apache/commons/compress/archivers/examples/ExpandCli.java
new file mode 100644
index 0000000..fd264ce
--- /dev/null
+++ b/src/main/java/org/apache/commons/compress/archivers/examples/ExpandCli.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.compress.archivers.examples;
+
+import java.io.File;
+import java.io.IOException;
+import org.apache.commons.compress.archivers.ArchiveException;
+
+/**
+ * Simple command line tool that extracts an archive into a directory.
+ *
+ * <p>Usage: <code>ExpandCli archive dir [format]</code></p>
+ * @since 1.17
+ */
+public class ExpandCli {
+
+ public static void main(String[] args) throws IOException, ArchiveException {
+ if (args.length < 2 || args.length > 3) {
+ System.err.println("Usage: ExpandCli dir archive [format]");
+ System.exit(1);
+ } else if (args.length == 2) {
+ try (ArchiveEntrySource source = ArchiveSources.forFile(new File(args[0])).detectFormat()) {
+ Expand.source(source).to(new DirectorySink(new File(args[1])));
+ }
+ } else {
+ try (ArchiveEntrySource source = ArchiveSources.forFile(new File(args[0])).withFormat(args[2])) {
+ Expand.source(source).to(new DirectorySink(new File(args[1])));
+ }
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/33558253/src/main/java/org/apache/commons/compress/archivers/examples/SevenZArchiveEntrySource.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/compress/archivers/examples/SevenZArchiveEntrySource.java b/src/main/java/org/apache/commons/compress/archivers/examples/SevenZArchiveEntrySource.java
new file mode 100644
index 0000000..9f38b38
--- /dev/null
+++ b/src/main/java/org/apache/commons/compress/archivers/examples/SevenZArchiveEntrySource.java
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.compress.archivers.examples;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.channels.SeekableByteChannel;
+import java.util.NoSuchElementException;
+import org.apache.commons.compress.archivers.ArchiveEntry;
+import org.apache.commons.compress.archivers.ArchiveException;
+import org.apache.commons.compress.utils.NoCloseInputStream;
+import org.apache.commons.compress.archivers.sevenz.SevenZFile;
+
+/**
+ * Supplier based on {@link SevenZFile}s.
+ * @since 1.17
+ */
+public class SevenZArchiveEntrySource implements ArchiveEntrySource {
+
+ private final SevenZFile sf;
+
+ public SevenZArchiveEntrySource(File f) throws IOException {
+ this(new SevenZFile(f));
+ }
+
+ public SevenZArchiveEntrySource(SeekableByteChannel c) throws IOException {
+ this(new SevenZFile(c));
+ }
+
+ public SevenZArchiveEntrySource(SevenZFile sf) {
+ this.sf = sf;
+ }
+
+ @Override
+ public ThrowingIterator<ChainPayload<ArchiveEntry>> get() throws IOException {
+ return new SevenZFileIterator(sf);
+ }
+
+ @Override
+ public void close() throws IOException {
+ sf.close();
+ }
+
+ @Override
+ public Filter<ArchiveEntry> skipUnreadable() {
+ return new Filter<ArchiveEntry>() {
+ @Override
+ public boolean accept(String entryName, ArchiveEntry entry) {
+ return true;
+ }
+ };
+ }
+
+ private static class SevenZFileIterator implements ThrowingIterator<ChainPayload<ArchiveEntry>> {
+ private final SevenZFile sf;
+ private ArchiveEntry nextEntry;
+ private boolean nextEntryConsumed;
+ SevenZFileIterator(SevenZFile sf) throws IOException {
+ this.sf = sf;
+ nextEntry = sf.getNextEntry();
+ nextEntryConsumed = false;
+ }
+
+ @Override
+ public boolean hasNext() throws IOException {
+ if (nextEntry == null || nextEntryConsumed) {
+ nextEntry = sf.getNextEntry();
+ nextEntryConsumed = false;
+ }
+ return nextEntry != null && !nextEntryConsumed;
+ }
+
+ @Override
+ public ChainPayload<ArchiveEntry> next() throws IOException {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ nextEntryConsumed = true;
+ return new ChainPayload(nextEntry, nextEntry.getName(), new Supplier<InputStream>() {
+ @Override
+ public InputStream get() throws IOException {
+ return new SevenZFileInputStream(sf);
+ }
+ });
+ }
+
+ }
+
+ private static class SevenZFileInputStream extends InputStream {
+ private final SevenZFile sf;
+ SevenZFileInputStream(SevenZFile sf) {
+ this.sf = sf;
+ }
+ @Override
+ public int read() throws IOException {
+ return sf.read();
+ }
+ @Override
+ public int read(byte[] b) throws IOException {
+ return read(b, 0, b.length);
+ }
+ @Override
+ public int read(final byte[] b, final int off, final int len) throws IOException {
+ return sf.read(b, off, len);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/33558253/src/main/java/org/apache/commons/compress/archivers/examples/StreamBasedArchiveEntrySource.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/compress/archivers/examples/StreamBasedArchiveEntrySource.java b/src/main/java/org/apache/commons/compress/archivers/examples/StreamBasedArchiveEntrySource.java
new file mode 100644
index 0000000..19aa55b
--- /dev/null
+++ b/src/main/java/org/apache/commons/compress/archivers/examples/StreamBasedArchiveEntrySource.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.compress.archivers.examples;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.NoSuchElementException;
+import org.apache.commons.compress.archivers.ArchiveEntry;
+import org.apache.commons.compress.archivers.ArchiveException;
+import org.apache.commons.compress.archivers.ArchiveInputStream;
+import org.apache.commons.compress.archivers.ArchiveStreamFactory;
+import org.apache.commons.compress.utils.NoCloseInputStream;
+
+/**
+ * Supplier based on {@link ArchiveInputStream}s.
+ * @since 1.17
+ */
+public class StreamBasedArchiveEntrySource implements ArchiveEntrySource {
+
+ private final ArchiveInputStream in;
+
+ public StreamBasedArchiveEntrySource(ArchiveInputStream in) {
+ this.in = in;
+ }
+
+ @Override
+ public ThrowingIterator<ChainPayload<ArchiveEntry>> get() throws IOException {
+ return new ArchiveInputStreamIterator(in);
+ }
+
+ @Override
+ public void close() throws IOException {
+ in.close();
+ }
+
+ @Override
+ public Filter<ArchiveEntry> skipUnreadable() {
+ return new Filter<ArchiveEntry>() {
+ @Override
+ public boolean accept(String entryName, ArchiveEntry entry) {
+ return in.canReadEntryData(entry);
+ }
+ };
+ }
+
+ private static class ArchiveInputStreamIterator implements ThrowingIterator<ChainPayload<ArchiveEntry>> {
+ private final ArchiveInputStream in;
+ private ArchiveEntry nextEntry;
+ private boolean nextEntryConsumed;
+ ArchiveInputStreamIterator(ArchiveInputStream in) throws IOException {
+ this.in = in;
+ nextEntry = in.getNextEntry();
+ nextEntryConsumed = false;
+ }
+
+ @Override
+ public boolean hasNext() throws IOException {
+ if (nextEntry == null || nextEntryConsumed) {
+ nextEntry = in.getNextEntry();
+ nextEntryConsumed = false;
+ }
+ return nextEntry != null && !nextEntryConsumed;
+ }
+
+ @Override
+ public ChainPayload<ArchiveEntry> next() throws IOException {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ nextEntryConsumed = true;
+ return new ChainPayload(nextEntry, nextEntry.getName(), new Supplier<InputStream>() {
+ @Override
+ public InputStream get() throws IOException {
+ return new NoCloseInputStream(in);
+ }
+ });
+ }
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/33558253/src/main/java/org/apache/commons/compress/archivers/examples/ZipArchiveEntrySource.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/compress/archivers/examples/ZipArchiveEntrySource.java b/src/main/java/org/apache/commons/compress/archivers/examples/ZipArchiveEntrySource.java
new file mode 100644
index 0000000..d5e84bc
--- /dev/null
+++ b/src/main/java/org/apache/commons/compress/archivers/examples/ZipArchiveEntrySource.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.compress.archivers.examples;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.channels.SeekableByteChannel;
+import java.util.Enumeration;
+import java.util.NoSuchElementException;
+import org.apache.commons.compress.archivers.ArchiveEntry;
+import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
+import org.apache.commons.compress.archivers.zip.ZipFile;
+
+/**
+ * Supplier based on {@link ZipFile}s.
+ * @since 1.17
+ */
+public class ZipArchiveEntrySource implements ArchiveEntrySource {
+
+ private final ZipFile zf;
+
+ public ZipArchiveEntrySource(File f) throws IOException {
+ this(new ZipFile(f));
+ }
+
+ public ZipArchiveEntrySource(SeekableByteChannel c) throws IOException {
+ this(new ZipFile(c));
+ }
+
+ public ZipArchiveEntrySource(ZipFile file) {
+ zf = file;
+ }
+
+ @Override
+ public ThrowingIterator<ChainPayload<ArchiveEntry>> get() throws IOException {
+ return new ZipFileIterator(zf, zf.getEntries());
+ }
+
+ @Override
+ public void close() throws IOException {
+ zf.close();
+ }
+
+ @Override
+ public Filter<ArchiveEntry> skipUnreadable() {
+ return new Filter<ArchiveEntry>() {
+ @Override
+ public boolean accept(String entryName, ArchiveEntry entry) {
+ return entry instanceof ZipArchiveEntry && zf.canReadEntryData((ZipArchiveEntry) entry);
+ }
+ };
+ }
+
+ private static class ZipFileIterator implements ThrowingIterator<ChainPayload<ArchiveEntry>> {
+ private final ZipFile zf;
+ private final Enumeration<ZipArchiveEntry> iter;
+ ZipFileIterator(ZipFile zf, Enumeration<ZipArchiveEntry> iter) {
+ this.zf = zf;
+ this.iter = iter;
+ }
+
+ @Override
+ public boolean hasNext() throws IOException {
+ return iter.hasMoreElements();
+ }
+
+ @Override
+ public ChainPayload<ArchiveEntry> next() throws IOException {
+ final ZipArchiveEntry z = iter.nextElement();
+ return new ChainPayload(z, z.getName(), new Supplier<InputStream>() {
+ @Override
+ public InputStream get() throws IOException {
+ return zf.getInputStream(z);
+ }
+ });
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/33558253/src/main/java/org/apache/commons/compress/utils/NoCloseInputStream.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/compress/utils/NoCloseInputStream.java b/src/main/java/org/apache/commons/compress/utils/NoCloseInputStream.java
new file mode 100644
index 0000000..bdc0ee9
--- /dev/null
+++ b/src/main/java/org/apache/commons/compress/utils/NoCloseInputStream.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.compress.utils;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Wrapper that overrides {@link #close} so that it doesn't close the
+ * underlying stream.
+ *
+ * @since 1.17
+ */
+public class NoCloseInputStream extends FilterInputStream {
+
+ public NoCloseInputStream(InputStream in) {
+ super(in);
+ }
+
+ /**
+ * This method does nothing.
+ */
+ public void close() {
+ // do not close the stream
+ }
+}
[2/2] commons-compress git commit: COMPRESS-118 make listing just
another sink for expanding
Posted by bo...@apache.org.
COMPRESS-118 make listing just another sink for expanding
Project: http://git-wip-us.apache.org/repos/asf/commons-compress/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-compress/commit/75a7edc7
Tree: http://git-wip-us.apache.org/repos/asf/commons-compress/tree/75a7edc7
Diff: http://git-wip-us.apache.org/repos/asf/commons-compress/diff/75a7edc7
Branch: refs/heads/master
Commit: 75a7edc742215c3354befe8fc0ec6d4ffe3bd663
Parents: 3355825
Author: Stefan Bodewig <bo...@apache.org>
Authored: Mon Apr 30 06:32:20 2018 +0200
Committer: Stefan Bodewig <bo...@apache.org>
Committed: Mon Apr 30 06:32:20 2018 +0200
----------------------------------------------------------------------
pom.xml | 2 +-
.../compress/archivers/examples/ListerCli.java | 68 ++++++++++++++++++++
2 files changed, 69 insertions(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/75a7edc7/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index c3eff8e..85ee514 100644
--- a/pom.xml
+++ b/pom.xml
@@ -329,7 +329,7 @@ Brotli, Zstandard and ar, cpio, jar, tar, zip, dump, 7z, arj.
<configuration>
<archive>
<manifestEntries>
- <Main-Class>org.apache.commons.compress.archivers.Lister</Main-Class>
+ <Main-Class>org.apache.commons.compress.archivers.examples.ListerCli</Main-Class>
<Extension-Name>org.apache.commons.compress</Extension-Name>
<Automatic-Module-Name>${commons.module.name}</Automatic-Module-Name>
</manifestEntries>
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/75a7edc7/src/main/java/org/apache/commons/compress/archivers/examples/ListerCli.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/compress/archivers/examples/ListerCli.java b/src/main/java/org/apache/commons/compress/archivers/examples/ListerCli.java
new file mode 100644
index 0000000..36f6efa
--- /dev/null
+++ b/src/main/java/org/apache/commons/compress/archivers/examples/ListerCli.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.commons.compress.archivers.examples;
+
+import java.io.File;
+import org.apache.commons.compress.archivers.ArchiveEntry;
+
+/**
+ * Simple command line application that lists the contents of an archive.
+ *
+ * <p>The name of the archive must be given as a command line argument.</p>
+ * <p>The optional second argument defines the archive type, in case the format is not recognized.</p>
+ *
+ * @since 1.17
+ */
+public final class ListerCli {
+
+ public static void main(final String[] args) throws Exception {
+ if (args.length == 0) {
+ usage();
+ return;
+ }
+ System.out.println("Analysing " + args[0]);
+ final Sink<ArchiveEntry> sink = new Sink<ArchiveEntry>() {
+ @Override
+ public void consume(ChainPayload<ArchiveEntry> payload) {
+ System.out.println(payload.getEntry().getName());
+ }
+ @Override
+ public void close() {
+ }
+ };
+
+ final File f = new File(args[0]);
+ if (!f.isFile()) {
+ System.err.println(f + " doesn't exist or is a directory");
+ } else if (args.length == 1) {
+ try (ArchiveEntrySource source = ArchiveSources.forFile(f).detectFormat()) {
+ Expand.source(source).to(sink);
+ }
+ } else {
+ try (ArchiveEntrySource source = ArchiveSources.forFile(f).withFormat(args[1])) {
+ Expand.source(source).to(sink);
+ }
+ }
+ }
+
+ private static void usage() {
+ System.out.println("Parameters: archive-name [archive-type]");
+ }
+
+}