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 2017/04/18 14:40:47 UTC
[2/4] commons-compress git commit: COMPRESS-385, add
ArchiveStreamFactory; undo boneheaded RELEASE-NOTES.txt fiasco.
COMPRESS-385, add ArchiveStreamFactory; undo boneheaded RELEASE-NOTES.txt fiasco.
Project: http://git-wip-us.apache.org/repos/asf/commons-compress/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-compress/commit/2cf57511
Tree: http://git-wip-us.apache.org/repos/asf/commons-compress/tree/2cf57511
Diff: http://git-wip-us.apache.org/repos/asf/commons-compress/diff/2cf57511
Branch: refs/heads/master
Commit: 2cf575115748e9865daaa369507019141573b86c
Parents: 30fce9d
Author: tballison <ta...@mitre.org>
Authored: Fri Apr 14 12:35:01 2017 -0400
Committer: Stefan Bodewig <bo...@apache.org>
Committed: Tue Apr 18 14:40:25 2017 +0200
----------------------------------------------------------------------
RELEASE-NOTES.txt | 12 --
src/changes/changes.xml | 4 +
.../archivers/ArchiveStreamFactory.java | 110 +++++++++++--------
.../compressors/CompressorStreamFactory.java | 2 +-
.../commons/compress/MockEvilInputStream.java | 39 +++++++
.../archivers/ArchiveStreamFactoryTest.java | 44 ++++++++
.../compressors/DetectCompressorTestCase.java | 21 +---
7 files changed, 158 insertions(+), 74 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/2cf57511/RELEASE-NOTES.txt
----------------------------------------------------------------------
diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index b16a4ea..21c9c4c 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -5,18 +5,6 @@ compression and archive formats. These include: bzip2, gzip, pack200,
lzma, xz, Snappy, traditional Unix Compress, DEFLATE and ar, cpio,
jar, tar, zip, dump, 7z, arj.
-Release 1.14
-------------
-
-Commons Compress 1.13 is the first version to require Java 7 at
-runtime.
-
-Changes in this version include:
-
-New features:
-o detect(InputStream) now available in CompressorStreamFactory
- Issue: Compress-385.
-
Release 1.13
------------
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/2cf57511/src/changes/changes.xml
----------------------------------------------------------------------
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 44d57f0..f1ac318 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -44,6 +44,10 @@ The <action> type attribute can be add,update,fix,remove.
<body>
<release version="1.14" date="not released, yet"
description="Release 1.14">
+ <action issue="COMPRESS-385" type="add" date="2017-04-14">
+ Add static detect(InputStream in) to CompressorStreamFactory
+ and ArchiveStreamFactory
+ </action>
<action issue="COMPRESS-378" type="fix" date="2017-01-09">
SnappyCompressorInputStream slides the window too early
leading to ArrayIndexOutOfBoundsExceptions for some streams.
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/2cf57511/src/main/java/org/apache/commons/compress/archivers/ArchiveStreamFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/compress/archivers/ArchiveStreamFactory.java b/src/main/java/org/apache/commons/compress/archivers/ArchiveStreamFactory.java
index 6ca0437..cc51458 100644
--- a/src/main/java/org/apache/commons/compress/archivers/ArchiveStreamFactory.java
+++ b/src/main/java/org/apache/commons/compress/archivers/ArchiveStreamFactory.java
@@ -473,6 +473,16 @@ public class ArchiveStreamFactory implements ArchiveStreamProvider {
*/
public ArchiveInputStream createArchiveInputStream(final InputStream in)
throws ArchiveException {
+ return createArchiveInputStream(detect(in), in);
+ }
+
+ /**
+ * Try to determine the type of Archiver
+ * @param in input stream
+ * @return type of archiver if found
+ * @throws ArchiveException if an archiver cannot be detected in the stream
+ */
+ public static String detect(InputStream in) throws ArchiveException {
if (in == null) {
throw new IllegalArgumentException("Stream must not be null.");
}
@@ -483,62 +493,72 @@ public class ArchiveStreamFactory implements ArchiveStreamProvider {
final byte[] signature = new byte[SIGNATURE_SIZE];
in.mark(signature.length);
+ int signatureLength = -1;
try {
- int signatureLength = IOUtils.readFully(in, signature);
+ signatureLength = IOUtils.readFully(in, signature);
in.reset();
- if (ZipArchiveInputStream.matches(signature, signatureLength)) {
- return createArchiveInputStream(ZIP, in);
- } else if (JarArchiveInputStream.matches(signature, signatureLength)) {
- return createArchiveInputStream(JAR, in);
- } else if (ArArchiveInputStream.matches(signature, signatureLength)) {
- return createArchiveInputStream(AR, in);
- } else if (CpioArchiveInputStream.matches(signature, signatureLength)) {
- return createArchiveInputStream(CPIO, in);
- } else if (ArjArchiveInputStream.matches(signature, signatureLength)) {
- return createArchiveInputStream(ARJ, in);
- } else if (SevenZFile.matches(signature, signatureLength)) {
- throw new StreamingNotSupportedException(SEVEN_Z);
- }
+ } catch (IOException e) {
+ throw new ArchiveException("IOException while reading signature.");
+ }
- // Dump needs a bigger buffer to check the signature;
- final byte[] dumpsig = new byte[DUMP_SIGNATURE_SIZE];
- in.mark(dumpsig.length);
+ if (JarArchiveInputStream.matches(signature, signatureLength)) {
+ return JAR;
+ } else if (ZipArchiveInputStream.matches(signature, signatureLength)) {
+ return ZIP;
+ } else if (ArArchiveInputStream.matches(signature, signatureLength)) {
+ return AR;
+ } else if (CpioArchiveInputStream.matches(signature, signatureLength)) {
+ return CPIO;
+ } else if (ArjArchiveInputStream.matches(signature, signatureLength)) {
+ return ARJ;
+ } else if (SevenZFile.matches(signature, signatureLength)) {
+ throw new StreamingNotSupportedException(SEVEN_Z);
+ }
+
+ // Dump needs a bigger buffer to check the signature;
+ final byte[] dumpsig = new byte[DUMP_SIGNATURE_SIZE];
+ in.mark(dumpsig.length);
+ try {
signatureLength = IOUtils.readFully(in, dumpsig);
in.reset();
- if (DumpArchiveInputStream.matches(dumpsig, signatureLength)) {
- return createArchiveInputStream(DUMP, in);
- }
+ } catch (IOException e) {
+ throw new ArchiveException("IOException while reading dump signature");
+ }
+ if (DumpArchiveInputStream.matches(dumpsig, signatureLength)) {
+ return DUMP;
+ }
- // Tar needs an even bigger buffer to check the signature; read the first block
- final byte[] tarHeader = new byte[TAR_HEADER_SIZE];
- in.mark(tarHeader.length);
+ // Tar needs an even bigger buffer to check the signature; read the first block
+ final byte[] tarHeader = new byte[TAR_HEADER_SIZE];
+ in.mark(tarHeader.length);
+ try {
signatureLength = IOUtils.readFully(in, tarHeader);
in.reset();
- if (TarArchiveInputStream.matches(tarHeader, signatureLength)) {
- return createArchiveInputStream(TAR, in);
- }
- // COMPRESS-117 - improve auto-recognition
- if (signatureLength >= TAR_HEADER_SIZE) {
- TarArchiveInputStream tais = null;
- try {
- tais = new TarArchiveInputStream(new ByteArrayInputStream(tarHeader));
- // COMPRESS-191 - verify the header checksum
- if (tais.getNextTarEntry().isCheckSumOK()) {
- return createArchiveInputStream(TAR, in);
- }
- } catch (final Exception e) { // NOPMD
- // can generate IllegalArgumentException as well
- // as IOException
- // autodetection, simply not a TAR
- // ignored
- } finally {
- IOUtils.closeQuietly(tais);
+ } catch (IOException e) {
+ throw new ArchiveException("IOException while reading tar signature");
+ }
+ if (TarArchiveInputStream.matches(tarHeader, signatureLength)) {
+ return TAR;
+ }
+
+ // COMPRESS-117 - improve auto-recognition
+ if (signatureLength >= TAR_HEADER_SIZE) {
+ TarArchiveInputStream tais = null;
+ try {
+ tais = new TarArchiveInputStream(new ByteArrayInputStream(tarHeader));
+ // COMPRESS-191 - verify the header checksum
+ if (tais.getNextTarEntry().isCheckSumOK()) {
+ return TAR;
}
+ } catch (final Exception e) { // NOPMD
+ // can generate IllegalArgumentException as well
+ // as IOException
+ // autodetection, simply not a TAR
+ // ignored
+ } finally {
+ IOUtils.closeQuietly(tais);
}
- } catch (final IOException e) {
- throw new ArchiveException("Could not use reset and mark operations.", e);
}
-
throw new ArchiveException("No Archiver found for the stream signature");
}
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/2cf57511/src/main/java/org/apache/commons/compress/compressors/CompressorStreamFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/compress/compressors/CompressorStreamFactory.java b/src/main/java/org/apache/commons/compress/compressors/CompressorStreamFactory.java
index c347cca..87c1209 100644
--- a/src/main/java/org/apache/commons/compress/compressors/CompressorStreamFactory.java
+++ b/src/main/java/org/apache/commons/compress/compressors/CompressorStreamFactory.java
@@ -400,7 +400,7 @@ public class CompressorStreamFactory implements CompressorStreamProvider {
signatureLength = IOUtils.readFully(in, signature);
in.reset();
} catch (IOException e) {
- throw new CompressorException("Failed while reading signature from InputStream.", e);
+ throw new CompressorException("IOException while reading signature.", e);
}
if (BZip2CompressorInputStream.matches(signature, signatureLength)) {
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/2cf57511/src/test/java/org/apache/commons/compress/MockEvilInputStream.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/compress/MockEvilInputStream.java b/src/test/java/org/apache/commons/compress/MockEvilInputStream.java
new file mode 100644
index 0000000..884cf50
--- /dev/null
+++ b/src/test/java/org/apache/commons/compress/MockEvilInputStream.java
@@ -0,0 +1,39 @@
+package org.apache.commons.compress;/*
+ * 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.
+ *
+ */
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Simple mock InputStream that always throws an IOException
+ * when {@link #read()} or {@link #read(byte[], int, int)}
+ * is called.
+ */
+public class MockEvilInputStream extends InputStream {
+
+ @Override
+ public int read() throws IOException {
+ throw new IOException("Evil");
+ }
+
+ @Override
+ public int read(byte[] bytes, int offset, int length) throws IOException {
+ throw new IOException("Evil");
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/2cf57511/src/test/java/org/apache/commons/compress/archivers/ArchiveStreamFactoryTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/compress/archivers/ArchiveStreamFactoryTest.java b/src/test/java/org/apache/commons/compress/archivers/ArchiveStreamFactoryTest.java
index 4236b28..27e2790 100644
--- a/src/test/java/org/apache/commons/compress/archivers/ArchiveStreamFactoryTest.java
+++ b/src/test/java/org/apache/commons/compress/archivers/ArchiveStreamFactoryTest.java
@@ -32,6 +32,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
+import org.apache.commons.compress.MockEvilInputStream;
import org.apache.commons.compress.archivers.arj.ArjArchiveInputStream;
import org.apache.commons.compress.archivers.cpio.CpioArchiveInputStream;
import org.apache.commons.compress.archivers.dump.DumpArchiveInputStream;
@@ -226,6 +227,49 @@ public class ArchiveStreamFactoryTest {
DUMP_DEFAULT = dflt;
}
+ @Test
+ public void testDetect() throws Exception {
+ for (String extension : new String[]{
+ ArchiveStreamFactory.ARJ,
+ ArchiveStreamFactory.CPIO,
+ ArchiveStreamFactory.DUMP,
+ ArchiveStreamFactory.JAR,
+ ArchiveStreamFactory.TAR,
+ //TODO-- figure out how to differentiate btwn JAR and ZIP
+ // ArchiveStreamFactory.ZIP
+ }) {
+ assertEquals(extension, detect("bla."+extension));
+ }
+
+ try {
+ ArchiveStreamFactory.detect(new BufferedInputStream(new ByteArrayInputStream(new byte[0])));
+ fail("shouldn't be able to detect empty stream");
+ } catch (ArchiveException e) {
+ assertEquals("No Archiver found for the stream signature", e.getMessage());
+ }
+
+ try {
+ ArchiveStreamFactory.detect(null);
+ fail("shouldn't be able to detect null stream");
+ } catch (IllegalArgumentException e) {
+ assertEquals("Stream must not be null.", e.getMessage());
+ }
+
+ try {
+ ArchiveStreamFactory.detect(new BufferedInputStream(new MockEvilInputStream()));
+ fail("Expected ArchiveException");
+ } catch (ArchiveException e) {
+ assertEquals("IOException while reading signature.", e.getMessage());
+ }
+ }
+
+ private String detect(String resource) throws IOException, ArchiveException {
+ try(InputStream in = new BufferedInputStream(new FileInputStream(
+ getFile(resource)))) {
+ return ArchiveStreamFactory.detect(in);
+ }
+ }
+
static final TestData[] TESTS = {
new TestData("bla.arj", ArchiveStreamFactory.ARJ, false, ARJ_DEFAULT, FACTORY, "charsetName"),
new TestData("bla.arj", ArchiveStreamFactory.ARJ, false, "UTF-8", FACTORY_UTF8, "charsetName"),
http://git-wip-us.apache.org/repos/asf/commons-compress/blob/2cf57511/src/test/java/org/apache/commons/compress/compressors/DetectCompressorTestCase.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/compress/compressors/DetectCompressorTestCase.java b/src/test/java/org/apache/commons/compress/compressors/DetectCompressorTestCase.java
index 187d931..8ccf579 100644
--- a/src/test/java/org/apache/commons/compress/compressors/DetectCompressorTestCase.java
+++ b/src/test/java/org/apache/commons/compress/compressors/DetectCompressorTestCase.java
@@ -31,6 +31,7 @@ import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
+import org.apache.commons.compress.MockEvilInputStream;
import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
import org.apache.commons.compress.compressors.deflate.DeflateCompressorInputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
@@ -121,6 +122,7 @@ public final class DetectCompressorTestCase {
@Test
public void testDetect() throws Exception {
+
assertEquals(CompressorStreamFactory.BZIP2, detect("bla.txt.bz2"));
assertEquals(CompressorStreamFactory.GZIP, detect("bla.tgz"));
assertEquals(CompressorStreamFactory.PACK200, detect("bla.pack"));
@@ -131,7 +133,7 @@ public final class DetectCompressorTestCase {
CompressorStreamFactory.detect(new BufferedInputStream(new ByteArrayInputStream(new byte[0])));
fail("shouldn't be able to detect empty stream");
} catch (CompressorException e) {
- assertTrue(e.getMessage().contains("No Compressor found"));
+ assertEquals("No Compressor found for the stream signature.", e.getMessage());
}
try {
@@ -142,10 +144,10 @@ public final class DetectCompressorTestCase {
}
try {
- CompressorStreamFactory.detect(new BufferedInputStream(new BadInputStream()));
+ CompressorStreamFactory.detect(new BufferedInputStream(new MockEvilInputStream()));
fail("Expected IOException");
} catch (CompressorException e) {
- assertEquals("Failed while reading signature from InputStream.", e.getMessage());
+ assertEquals("IOException while reading signature.", e.getMessage());
}
@@ -216,17 +218,4 @@ public final class DetectCompressorTestCase {
new BufferedInputStream(new FileInputStream(
getFile(resource))));
}
-
- private static class BadInputStream extends InputStream {
- @Override
- public int read() throws IOException {
- throw new IOException("Bad");
- }
-
- @Override
- public int read(byte[] bytes, int offset, int length) throws IOException {
- throw new IOException("Bad");
- }
- }
-
}