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/05/02 04:16:45 UTC
commons-compress git commit: COMPRESS-443 provide a custom
InputStream for special skip problems
Repository: commons-compress
Updated Branches:
refs/heads/master ffb618d50 -> e15c80ae3
COMPRESS-443 provide a custom InputStream for special skip problems
Project: http://git-wip-us.apache.org/repos/asf/commons-compress/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-compress/commit/e15c80ae
Tree: http://git-wip-us.apache.org/repos/asf/commons-compress/tree/e15c80ae
Diff: http://git-wip-us.apache.org/repos/asf/commons-compress/diff/e15c80ae
Branch: refs/heads/master
Commit: e15c80ae3fafe8903f220a6232c37a77b919c60e
Parents: ffb618d
Author: Stefan Bodewig <bo...@apache.org>
Authored: Wed May 2 06:16:14 2018 +0200
Committer: Stefan Bodewig <bo...@apache.org>
Committed: Wed May 2 06:16:14 2018 +0200
----------------------------------------------------------------------
src/changes/changes.xml | 4 +
.../utils/SkipShieldingInputStream.java | 51 +++++++++++
src/site/xdoc/limitations.xml | 15 ++++
.../utils/SkipShieldingInputStreamTest.java | 91 ++++++++++++++++++++
4 files changed, 161 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/e15c80ae/src/changes/changes.xml
----------------------------------------------------------------------
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 11f0193..44a69ab 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -74,6 +74,10 @@ The <action> type attribute can be add,update,fix,remove.
Added a unit test that is supposed to fail if we break the
OSGi manifest entries again.
</action>
+ <action issue="COMPRESS-443" type="add" date="2018-05-02">
+ Add a new SkipShieldingInputStream class that can be used wit
+ streams that throw an IOException whne skip is invoked.
+ </action>
</release>
<release version="1.16.1" date="2018-02-10"
description="Release 1.16.1">
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/e15c80ae/src/main/java/org/apache/commons/compress/utils/SkipShieldingInputStream.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/compress/utils/SkipShieldingInputStream.java b/src/main/java/org/apache/commons/compress/utils/SkipShieldingInputStream.java
new file mode 100644
index 0000000..09b5ce2
--- /dev/null
+++ b/src/main/java/org/apache/commons/compress/utils/SkipShieldingInputStream.java
@@ -0,0 +1,51 @@
+/*
+ * 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;
+
+/**
+ * A wrapper that overwrites {@link #skip} and delegates to {@link #read} instead.
+ *
+ * <p>Some implementations of {@link InputStream} implement {@link
+ * InputStream#skip} in a way that throws an expecption if the stream
+ * is not seekable - {@link System#in System.in} is known to behave
+ * that way. For such a stream it is impossible to invoke skip at all
+ * and you have to read from the stream (and discard the data read)
+ * instead. Skipping is potentially much faster than reading so we do
+ * want to invoke {@code skip} when possible. We provide this class so
+ * you can wrap your own {@link InputStream} in it if you encounter
+ * problems with {@code skip} throwing an excpetion.</p>
+ *
+ * @since 1.17
+ */
+public class SkipShieldingInputStream extends FilterInputStream {
+ private static final int SKIP_BUFFER_SIZE = 8192;
+ // we can use a shared buffer as the content is discarded anyway
+ private static final byte[] SKIP_BUFFER = new byte[SKIP_BUFFER_SIZE];
+ public SkipShieldingInputStream(InputStream in) {
+ super(in);
+ }
+
+ @Override
+ public long skip(long n) throws IOException {
+ return n < 0 ? 0 : read(SKIP_BUFFER, 0, (int) Math.min(n, SKIP_BUFFER_SIZE));
+ }
+}
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/e15c80ae/src/site/xdoc/limitations.xml
----------------------------------------------------------------------
diff --git a/src/site/xdoc/limitations.xml b/src/site/xdoc/limitations.xml
index 9fc45f6..c78adcc 100644
--- a/src/site/xdoc/limitations.xml
+++ b/src/site/xdoc/limitations.xml
@@ -25,6 +25,21 @@
Commons Compress™ grouped by the archiving/compression
format they apply to.</p>
+ <section name="General">
+ <ul>
+ <li>Several implementations of decompressors and unarchivers will
+ invoke <a
+ href="https://docs.oracle.com/javase/10/docs/api/java/io/InputStream.html#skip(long)"><code>skip</code></a>
+ on the underlying <code>InputStream</code> which may throw an
+ <code>IOException</code> in some stream implementations. One
+ known case where this happens is when using
+ <code>System.in</code> as input. If you encounter an
+ exception with a message like "Illegal seek" we recommend you
+ wrap your stream in a <code>SkipShieldingInputStream</code>
+ from our utils package before passing it to Compress.</li>
+ </ul>
+ </section>
+
<section name="7Z">
<ul>
<li>the format requires the otherwise optional <a
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/e15c80ae/src/test/java/org/apache/commons/compress/utils/SkipShieldingInputStreamTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/compress/utils/SkipShieldingInputStreamTest.java b/src/test/java/org/apache/commons/compress/utils/SkipShieldingInputStreamTest.java
new file mode 100644
index 0000000..5ae69cf
--- /dev/null
+++ b/src/test/java/org/apache/commons/compress/utils/SkipShieldingInputStreamTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.IOException;
+import java.io.InputStream;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class SkipShieldingInputStreamTest {
+
+ @Test
+ public void skipDelegatesToRead() throws IOException {
+ try (InputStream i = new SkipShieldingInputStream(new InputStream() {
+ @Override
+ public long skip(long n) {
+ Assert.fail("skip invoked");
+ return -1;
+ }
+ @Override
+ public int read() {
+ return -1;
+ }
+ @Override
+ public int read(byte[] b, int off, int len) {
+ return len;
+ }
+ })) {
+ Assert.assertEquals(100, i.skip(100));
+ }
+ }
+
+ @Test
+ public void skipHasAnUpperBoundOnRead() throws IOException {
+ try (InputStream i = new SkipShieldingInputStream(new InputStream() {
+ @Override
+ public long skip(long n) {
+ Assert.fail("skip invoked");
+ return -1;
+ }
+ @Override
+ public int read() {
+ return -1;
+ }
+ @Override
+ public int read(byte[] b, int off, int len) {
+ return len;
+ }
+ })) {
+ Assert.assertTrue(Integer.MAX_VALUE > i.skip(Long.MAX_VALUE));
+ }
+ }
+
+ @Test
+ public void skipSwallowsNegativeArguments() throws IOException {
+ try (InputStream i = new SkipShieldingInputStream(new InputStream() {
+ @Override
+ public long skip(long n) {
+ Assert.fail("skip invoked");
+ return -1;
+ }
+ @Override
+ public int read() {
+ return -1;
+ }
+ @Override
+ public int read(byte[] b, int off, int len) {
+ Assert.fail("read invoked");
+ return len;
+ }
+ })) {
+ Assert.assertEquals(0, i.skip(Long.MIN_VALUE));
+ }
+ }
+
+}