COMPRESS-272 add auto-detect for .Z

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/compress/trunk@1586869 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 5f3b83a..4cc18fa 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -51,6 +51,10 @@
         The snappy, ar and tar inputstreams might fail to read from a
         non-buffered stream in certain cases.
       </action>
+      <action type="add" date="2014-04-12" issue="COMPRESS-272">
+        CompressorStreamFactory can now auto-detect Unix compress
+        (".Z") streams.
+      </action>
     </release>
     <release version="1.8" date="2014-03-12"
              description="Release 1.8">
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 482cbcd..0d7cdaa 100644
--- a/src/main/java/org/apache/commons/compress/compressors/CompressorStreamFactory.java
+++ b/src/main/java/org/apache/commons/compress/compressors/CompressorStreamFactory.java
@@ -179,6 +179,10 @@
                 return new FramedSnappyCompressorInputStream(in);
             }
 
+            if (ZCompressorInputStream.matches(signature, signatureLength)) {
+                return new ZCompressorInputStream(in);
+            }
+
         } catch (IOException e) {
             throw new CompressorException("Failed to detect Compressor from InputStream.", e);
         }
diff --git a/src/main/java/org/apache/commons/compress/compressors/z/ZCompressorInputStream.java b/src/main/java/org/apache/commons/compress/compressors/z/ZCompressorInputStream.java
index 789448d..7e6104e 100644
--- a/src/main/java/org/apache/commons/compress/compressors/z/ZCompressorInputStream.java
+++ b/src/main/java/org/apache/commons/compress/compressors/z/ZCompressorInputStream.java
@@ -149,4 +149,20 @@
         }
     }
     
+    /**
+     * Checks if the signature matches what is expected for a Unix compress file.
+     * 
+     * @param signature
+     *            the bytes to check
+     * @param length
+     *            the number of bytes to check
+     * @return true, if this stream is a Unix compress compressed
+     * stream, false otherwise
+     * 
+     * @since 1.9
+     */
+    public static boolean matches(byte[] signature, int length) {
+        return length > 3 && signature[0] == MAGIC_1 && signature[1] == (byte) MAGIC_2;
+    }
+
 }
diff --git a/src/test/java/org/apache/commons/compress/compressors/ZTestCase.java b/src/test/java/org/apache/commons/compress/compressors/ZTestCase.java
index 01571e0..be14746 100644
--- a/src/test/java/org/apache/commons/compress/compressors/ZTestCase.java
+++ b/src/test/java/org/apache/commons/compress/compressors/ZTestCase.java
@@ -18,6 +18,7 @@
  */
 package org.apache.commons.compress.compressors;
 
+import java.io.BufferedInputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
@@ -47,6 +48,26 @@
         });
     }
 
+    public void testZUnarchiveViaAutoDetection() throws Exception {
+        testUnarchive(new StreamWrapper<CompressorInputStream>() {
+            public CompressorInputStream wrap(InputStream is) throws Exception {
+                return new CompressorStreamFactory()
+                    .createCompressorInputStream(new BufferedInputStream(is));
+            }
+        });
+    }
+
+    public void testMatches() throws Exception {
+        assertFalse(ZCompressorInputStream.matches(new byte[] { 1, 2, 3, 4 }, 4));
+        assertFalse(ZCompressorInputStream.matches(new byte[] { 0x1f, 2, 3, 4 }, 4));
+        assertFalse(ZCompressorInputStream.matches(new byte[] { 1, (byte)0x9d, 3, 4 },
+                                                   4));
+        assertFalse(ZCompressorInputStream.matches(new byte[] { 0x1f, (byte) 0x9d, 3, 4 },
+                                                   3));
+        assertTrue(ZCompressorInputStream.matches(new byte[] { 0x1f, (byte) 0x9d, 3, 4 },
+                                                  4));
+    }
+
     private void testUnarchive(StreamWrapper<CompressorInputStream> wrapper) throws Exception {
         final File input = getFile("bla.tar.Z");
         final File output = new File(dir, "bla.tar");