COMPRESS-306 ArchiveStreamFactory fails to pass on the encoding when creating some streams.

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/compress/trunk@1660245 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 428e0c7..0e6db4c 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -54,6 +54,15 @@
 This also changes the superclass of ZCompressorInputStream.    
 ">
 
+      <action issue="COMPRESS-306" type="fix">
+        ArchiveStreamFactory fails to pass on the encoding when creating some streams.
+        * ArjArchiveInputStream
+        * CpioArchiveInputStream
+        * DumpArchiveInputStream
+        * JarArchiveInputStream
+        * TarArchiveInputStream
+        * JarArchiveOutputStream
+      </action>
       <action issue="COMPRESS-302" type="fix">
         Restore immutability/thread-safety to ArchiveStreamFactory.
         The class is now immutable provided that the method setEntryEncoding is not used.
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 4aefb29..c73e665 100644
--- a/src/main/java/org/apache/commons/compress/archivers/ArchiveStreamFactory.java
+++ b/src/main/java/org/apache/commons/compress/archivers/ArchiveStreamFactory.java
@@ -150,10 +150,10 @@
     }
 
     /**
-     * Returns the encoding to use for arj, zip, dump, cpio and tar
-     * files, or null for the default.
+     * Returns the encoding to use for arj, jar, zip, dump, cpio and tar
+     * files, or null for the archiver default.
      *
-     * @return entry encoding, or null
+     * @return entry encoding, or null for the archiver default
      * @since 1.5
      */
     public String getEntryEncoding() {
@@ -161,9 +161,9 @@
     }
 
     /**
-     * Sets the encoding to use for arj, zip, dump, cpio and tar files. Use null for the default.
+     * Sets the encoding to use for arj, jar, zip, dump, cpio and tar files. Use null for the archiver default.
      * 
-     * @param entryEncoding the entry encoding, null uses the default.
+     * @param entryEncoding the entry encoding, null uses the archiver default.
      * @since 1.5
      * @deprecated 1.10 use {@link #ArchiveStreamFactory(String)} to specify the encoding
      * @throws IllegalStateException if the constructor {@link #ArchiveStreamFactory(String)} 
@@ -227,7 +227,11 @@
             }
         }
         if (JAR.equalsIgnoreCase(archiverName)) {
-            return new JarArchiveInputStream(in);
+            if (entryEncoding != null) {
+                return new JarArchiveInputStream(in, entryEncoding);
+            } else {
+                return new JarArchiveInputStream(in);
+            }
         }
         if (CPIO.equalsIgnoreCase(archiverName)) {
             if (entryEncoding != null) {
@@ -254,7 +258,7 @@
      * Create an archive output stream from an archiver name and an output stream.
      * 
      * @param archiverName the archive name,
-     * i.e. {@value #AR}, {@value #ZIP}, {@value #TAR}, {@value #JAR}, {@value #CPIO} or {@value #SEVEN_Z} 
+     * i.e. {@value #AR}, {@value #ZIP}, {@value #TAR}, {@value #JAR} or {@value #CPIO} 
      * @param out the output stream
      * @return the archive output stream
      * @throws ArchiveException if the archiver name is not known
@@ -290,7 +294,11 @@
             }
         }
         if (JAR.equalsIgnoreCase(archiverName)) {
-            return new JarArchiveOutputStream(out);
+            if (entryEncoding != null) {
+                return new JarArchiveOutputStream(out, entryEncoding);
+            } else {
+                return new JarArchiveOutputStream(out);
+            }
         }
         if (CPIO.equalsIgnoreCase(archiverName)) {
             if (entryEncoding != null) {
@@ -339,13 +347,25 @@
                     return new ZipArchiveInputStream(in);
                 }
             } else if (JarArchiveInputStream.matches(signature, signatureLength)) {
-                return new JarArchiveInputStream(in);
+                if (entryEncoding != null) {
+                    return new JarArchiveInputStream(in, entryEncoding);
+                } else {
+                    return new JarArchiveInputStream(in);
+                }
             } else if (ArArchiveInputStream.matches(signature, signatureLength)) {
                 return new ArArchiveInputStream(in);
             } else if (CpioArchiveInputStream.matches(signature, signatureLength)) {
-                return new CpioArchiveInputStream(in);
+                if (entryEncoding != null) {
+                    return new CpioArchiveInputStream(in, entryEncoding);
+                } else {
+                    return new CpioArchiveInputStream(in);
+                }
             } else if (ArjArchiveInputStream.matches(signature, signatureLength)) {
-                return new ArjArchiveInputStream(in);
+                if (entryEncoding != null) {
+                    return new ArjArchiveInputStream(in, entryEncoding);
+                } else {
+                    return new ArjArchiveInputStream(in);
+                }
             } else if (SevenZFile.matches(signature, signatureLength)) {
                 throw new StreamingNotSupportedException(SEVEN_Z);
             }
@@ -356,7 +376,7 @@
             signatureLength = IOUtils.readFully(in, dumpsig);
             in.reset();
             if (DumpArchiveInputStream.matches(dumpsig, signatureLength)) {
-                return new DumpArchiveInputStream(in);
+                return new DumpArchiveInputStream(in, entryEncoding);
             }
 
             // Tar needs an even bigger buffer to check the signature; read the first block
@@ -365,11 +385,7 @@
             signatureLength = IOUtils.readFully(in, tarheader);
             in.reset();
             if (TarArchiveInputStream.matches(tarheader, signatureLength)) {
-                if (entryEncoding != null) {
-                    return new TarArchiveInputStream(in, entryEncoding);
-                } else {
-                    return new TarArchiveInputStream(in);
-                }
+                return new TarArchiveInputStream(in, entryEncoding);
             }
             // COMPRESS-117 - improve auto-recognition
             if (signatureLength >= 512) {
@@ -378,7 +394,7 @@
                     tais = new TarArchiveInputStream(new ByteArrayInputStream(tarheader));
                     // COMPRESS-191 - verify the header checksum
                     if (tais.getNextTarEntry().isCheckSumOK()) {
-                        return new TarArchiveInputStream(in);
+                        return new TarArchiveInputStream(in, encoding);
                     }
                 } catch (Exception e) { // NOPMD
                     // can generate IllegalArgumentException as well
diff --git a/src/main/java/org/apache/commons/compress/archivers/cpio/CpioArchiveInputStream.java b/src/main/java/org/apache/commons/compress/archivers/cpio/CpioArchiveInputStream.java
index 0d7e4ba..915b56e 100644
--- a/src/main/java/org/apache/commons/compress/archivers/cpio/CpioArchiveInputStream.java
+++ b/src/main/java/org/apache/commons/compress/archivers/cpio/CpioArchiveInputStream.java
@@ -91,7 +91,10 @@
     /**
      * The encoding to use for filenames and labels.
      */
-    private final ZipEncoding encoding;
+    private final ZipEncoding zipEncoding;
+
+    // the provided encoding (for unit tests)
+    final String encoding;
 
     /**
      * Construct the cpio input stream with a blocksize of {@link
@@ -150,7 +153,8 @@
     public CpioArchiveInputStream(final InputStream in, int blockSize, String encoding) {
         this.in = in;
         this.blockSize = blockSize;
-        this.encoding = ZipEncodingHelper.getZipEncoding(encoding);
+        this.encoding = encoding;
+        this.zipEncoding = ZipEncodingHelper.getZipEncoding(encoding);
     }
 
     /**
@@ -444,7 +448,7 @@
         byte tmpBuffer[] = new byte[length - 1];
         readFully(tmpBuffer, 0, tmpBuffer.length);
         this.in.read();
-        return encoding.decode(tmpBuffer);
+        return zipEncoding.decode(tmpBuffer);
     }
 
     /**
diff --git a/src/main/java/org/apache/commons/compress/archivers/cpio/CpioArchiveOutputStream.java b/src/main/java/org/apache/commons/compress/archivers/cpio/CpioArchiveOutputStream.java
index ff86ddf..fc829ff 100644
--- a/src/main/java/org/apache/commons/compress/archivers/cpio/CpioArchiveOutputStream.java
+++ b/src/main/java/org/apache/commons/compress/archivers/cpio/CpioArchiveOutputStream.java
@@ -92,7 +92,10 @@
     /**
      * The encoding to use for filenames and labels.
      */
-    private final ZipEncoding encoding;
+    private final ZipEncoding zipEncoding;
+
+    // the provided encoding (for unit tests)
+    final String encoding;
 
     /**
      * Construct the cpio output stream with a specified format, a
@@ -157,7 +160,8 @@
         }
         this.entryFormat = format;
         this.blockSize = blockSize;
-        this.encoding = ZipEncodingHelper.getZipEncoding(encoding);
+        this.encoding = encoding;
+        this.zipEncoding = ZipEncodingHelper.getZipEncoding(encoding);
     }
 
     /**
@@ -534,7 +538,7 @@
      * @throws IOException if the string couldn't be written
      */
     private void writeCString(final String str) throws IOException {
-        ByteBuffer buf = encoding.encode(str);
+        ByteBuffer buf = zipEncoding.encode(str);
         final int len = buf.limit() - buf.position();
         out.write(buf.array(), buf.arrayOffset(), len);
         out.write('\0');
diff --git a/src/main/java/org/apache/commons/compress/archivers/dump/DumpArchiveInputStream.java b/src/main/java/org/apache/commons/compress/archivers/dump/DumpArchiveInputStream.java
index 6381e89..09431a4 100644
--- a/src/main/java/org/apache/commons/compress/archivers/dump/DumpArchiveInputStream.java
+++ b/src/main/java/org/apache/commons/compress/archivers/dump/DumpArchiveInputStream.java
@@ -74,7 +74,10 @@
     /**
      * The encoding to use for filenames and labels.
      */
-    private final ZipEncoding encoding;
+    private final ZipEncoding zipEncoding;
+
+    // the provided encoding (for unit tests)
+    final String encoding;
 
     /**
      * Constructor using the platform's default encoding for file
@@ -99,7 +102,8 @@
         throws ArchiveException {
         this.raw = new TapeInputStream(is);
         this.hasHitEOF = false;
-        this.encoding = ZipEncodingHelper.getZipEncoding(encoding);
+        this.encoding = encoding;
+        this.zipEncoding = ZipEncodingHelper.getZipEncoding(encoding);
 
         try {
             // read header, verify it's a dump archive.
@@ -110,7 +114,7 @@
             }
 
             // get summary information
-            summary = new DumpArchiveSummary(headerBytes, this.encoding);
+            summary = new DumpArchiveSummary(headerBytes, this.zipEncoding);
 
             // reset buffer with actual block size.
             raw.resetBlockSize(summary.getNTRec(), summary.isCompressed());
@@ -351,7 +355,7 @@
 
                 byte type = blockBuffer[i + 6];
 
-                String name = DumpArchiveUtil.decode(encoding, blockBuffer, i + 8, blockBuffer[i + 7]);
+                String name = DumpArchiveUtil.decode(zipEncoding, blockBuffer, i + 8, blockBuffer[i + 7]);
 
                 if (".".equals(name) || "..".equals(name)) {
                     // do nothing...
diff --git a/src/main/java/org/apache/commons/compress/archivers/jar/JarArchiveInputStream.java b/src/main/java/org/apache/commons/compress/archivers/jar/JarArchiveInputStream.java
index d051a4b..1ebac2f 100644
--- a/src/main/java/org/apache/commons/compress/archivers/jar/JarArchiveInputStream.java
+++ b/src/main/java/org/apache/commons/compress/archivers/jar/JarArchiveInputStream.java
@@ -32,10 +32,26 @@
  */
 public class JarArchiveInputStream extends ZipArchiveInputStream {
 
+    /**
+     * Creates an instance from the input stream using the default encoding.
+     * 
+     * @param inputStream the input stream to wrap
+     */
     public JarArchiveInputStream( final InputStream inputStream ) {
         super(inputStream);
     }
 
+    /**
+     * Creates an instance from the input stream using the specified encoding.
+     * 
+     * @param inputStream the input stream to wrap
+     * @param encoding the encoding to use
+     * @since 1.10
+     */
+    public JarArchiveInputStream( final InputStream inputStream, final String encoding ) {
+        super(inputStream, encoding);
+    }
+
     public JarArchiveEntry getNextJarEntry() throws IOException {
         ZipArchiveEntry entry = getNextZipEntry();
         return entry == null ? null : new JarArchiveEntry(entry);
diff --git a/src/main/java/org/apache/commons/compress/archivers/jar/JarArchiveOutputStream.java b/src/main/java/org/apache/commons/compress/archivers/jar/JarArchiveOutputStream.java
index f372ad7..96d0fbf 100644
--- a/src/main/java/org/apache/commons/compress/archivers/jar/JarArchiveOutputStream.java
+++ b/src/main/java/org/apache/commons/compress/archivers/jar/JarArchiveOutputStream.java
@@ -41,6 +41,18 @@
         super(out);
     }
 
+    /**
+     * Create and instance that wraps the output stream using the provided encoding.
+     * 
+     * @param out the output stream to wrap
+     * @param encoding the encoding to use. Use null for the platform default.
+     * @since 1.10
+     */
+    public JarArchiveOutputStream(final OutputStream out, final String encoding) {
+        super(out);
+        setEncoding(encoding);
+    }
+
     // @throws ClassCastException if entry is not an instance of ZipArchiveEntry
     @Override
     public void putArchiveEntry(ArchiveEntry ze) throws IOException {
diff --git a/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStream.java b/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStream.java
index 545d15c..c557007 100644
--- a/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStream.java
+++ b/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStream.java
@@ -73,7 +73,10 @@
     private TarArchiveEntry currEntry;
 
     /** The encoding of the file */
-    private final ZipEncoding encoding;
+    private final ZipEncoding zipEncoding;
+
+    // the provided encoding (for unit tests)
+    final String encoding;
 
     /**
      * Constructor for TarInputStream.
@@ -137,7 +140,8 @@
                                  String encoding) {
         this.is = is;
         this.hasHitEOF = false;
-        this.encoding = ZipEncodingHelper.getZipEncoding(encoding);
+        this.encoding = encoding;
+        this.zipEncoding = ZipEncodingHelper.getZipEncoding(encoding);
         this.recordSize = recordSize;
         this.blockSize = blockSize;
     }
@@ -271,7 +275,7 @@
         }
 
         try {
-            currEntry = new TarArchiveEntry(headerBuf, encoding);
+            currEntry = new TarArchiveEntry(headerBuf, zipEncoding);
         } catch (IllegalArgumentException e) {
             IOException ioe = new IOException("Error detected parsing the header");
             ioe.initCause(e);
@@ -289,7 +293,7 @@
                 // entry
                 return null;
             }
-            currEntry.setLinkName(encoding.decode(longLinkData));
+            currEntry.setLinkName(zipEncoding.decode(longLinkData));
         }
 
         if (currEntry.isGNULongNameEntry()) {
@@ -300,7 +304,7 @@
                 // entry
                 return null;
             }
-            currEntry.setName(encoding.decode(longNameData));
+            currEntry.setName(zipEncoding.decode(longNameData));
         }
 
         if (currEntry.isPaxHeader()){ // Process Pax headers
diff --git a/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveOutputStream.java b/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveOutputStream.java
index 1b134af..43525c8 100644
--- a/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveOutputStream.java
+++ b/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveOutputStream.java
@@ -84,7 +84,10 @@
 
     private final OutputStream out;
 
-    private final ZipEncoding encoding;
+    private final ZipEncoding zipEncoding;
+
+    // the provided encoding (for unit tests)
+    final String encoding;
 
     private boolean addPaxHeadersForNonAsciiNames = false;
     private static final ZipEncoding ASCII =
@@ -150,7 +153,8 @@
     public TarArchiveOutputStream(OutputStream os, int blockSize,
                                   int recordSize, String encoding) {
         out = new CountingOutputStream(os);
-        this.encoding = ZipEncodingHelper.getZipEncoding(encoding);
+        this.encoding = encoding;
+        this.zipEncoding = ZipEncodingHelper.getZipEncoding(encoding);
 
         this.assemLen = 0;
         this.assemBuf = new byte[recordSize];
@@ -301,7 +305,7 @@
             writePaxHeaders(entry, entryName, paxHeaders);
         }
 
-        entry.writeEntryHeader(recordBuf, encoding,
+        entry.writeEntryHeader(recordBuf, zipEncoding,
                                bigNumberMode == BIGNUMBER_STAR);
         writeRecord(recordBuf);
 
@@ -660,7 +664,7 @@
                                    Map<String, String> paxHeaders,
                                    String paxHeaderName, byte linkType, String fieldName)
         throws IOException {
-        final ByteBuffer encodedName = encoding.encode(name);
+        final ByteBuffer encodedName = zipEncoding.encode(name);
         final int len = encodedName.limit() - encodedName.position();
         if (len >= TarConstants.NAMELEN) {
 
diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java b/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java
index 226d29e..7a69141 100644
--- a/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java
+++ b/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java
@@ -61,6 +61,9 @@
     /** The zip encoding to use for filenames and the file comment. */
     private final ZipEncoding zipEncoding;
 
+    // the provided encoding (for unit tests)
+    final String encoding;
+
     /** Whether to look for and use Unicode extra fields. */
     private final boolean useUnicodeExtraFields;
 
@@ -139,6 +142,10 @@
 
     private int entriesRead = 0;
 
+    /**
+     * Create an instance using UTF-8 encoding
+     * @param inputStream the stream to wrap
+     */
     public ZipArchiveInputStream(InputStream inputStream) {
         this(inputStream, ZipEncodingHelper.UTF8);
     }
@@ -175,6 +182,7 @@
                                  String encoding,
                                  boolean useUnicodeExtraFields,
                                  boolean allowStoredEntriesWithDataDescriptor) {
+        this.encoding = encoding;
         zipEncoding = ZipEncodingHelper.getZipEncoding(encoding);
         this.useUnicodeExtraFields = useUnicodeExtraFields;
         in = new PushbackInputStream(inputStream, buf.capacity());
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 d7b47b1..0352fed 100644
--- a/src/test/java/org/apache/commons/compress/archivers/ArchiveStreamFactoryTest.java
+++ b/src/test/java/org/apache/commons/compress/archivers/ArchiveStreamFactoryTest.java
@@ -18,7 +18,9 @@
  */
 package org.apache.commons.compress.archivers;
 
+import static org.apache.commons.compress.AbstractTestCase.getFile;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -26,8 +28,15 @@
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.FileInputStream;
+import java.io.IOException;
 import java.io.InputStream;
+import java.lang.reflect.Field;
 
+import org.apache.commons.compress.archivers.arj.ArjArchiveInputStream;
+import org.apache.commons.compress.archivers.cpio.CpioArchiveInputStream;
+import org.apache.commons.compress.archivers.dump.DumpArchiveInputStream;
+import org.apache.commons.compress.archivers.jar.JarArchiveInputStream;
+import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
 import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
 import org.junit.Test;
 
@@ -147,4 +156,249 @@
             fis.close();
     	}
     }
+    
+    @Test
+    public void testEncodingCtor() {
+        ArchiveStreamFactory fac = new ArchiveStreamFactory();
+        assertNull(fac.getEntryEncoding());
+        fac = new ArchiveStreamFactory(null);
+        assertNull(fac.getEntryEncoding());
+        fac = new ArchiveStreamFactory("UTF-8");
+        assertEquals("UTF-8", fac.getEntryEncoding());
+    }
+
+    @Test
+    @SuppressWarnings("deprecation")
+    public void testEncodingDeprecated() {
+        ArchiveStreamFactory fac = new ArchiveStreamFactory();
+        assertNull(fac.getEntryEncoding());
+        fac.setEntryEncoding("UTF-8");
+        assertEquals("UTF-8", fac.getEntryEncoding());
+        fac.setEntryEncoding("US_ASCII");
+        assertEquals("US_ASCII", fac.getEntryEncoding());
+        fac = new ArchiveStreamFactory("UTF-8");
+        assertEquals("UTF-8", fac.getEntryEncoding());
+        try {
+            fac.setEntryEncoding("US_ASCII");
+            fail("Expected IllegalStateException");
+        } catch (IllegalStateException ise) {
+            // expected
+        }
+    }
+
+    static class TestData {
+        final String testFile;
+        final String expectedEncoding;
+        final ArchiveStreamFactory fac;
+        final String fieldName;
+        final String type;
+        final boolean hasOutputStream;
+        TestData(String testFile, String type, boolean hasOut, String expectedEncoding, ArchiveStreamFactory fac, String fieldName) {
+            this.testFile = testFile;
+            this.expectedEncoding = expectedEncoding;
+            this.fac = fac;
+            this.fieldName = fieldName;
+            this.type = type;
+            this.hasOutputStream = hasOut;
+        }
+    }
+
+    @SuppressWarnings("deprecation") // test of deprecated method
+    static ArchiveStreamFactory getFactory(String entryEncoding) {
+        ArchiveStreamFactory fac = new ArchiveStreamFactory();
+        fac.setEntryEncoding(entryEncoding);
+        return fac;
+    }
+    // The different factory types
+    private static final ArchiveStreamFactory FACTORY = new ArchiveStreamFactory();
+    private static final ArchiveStreamFactory FACTORY_UTF8 = new ArchiveStreamFactory("UTF-8");
+    private static final ArchiveStreamFactory FACTORY_ASCII = new ArchiveStreamFactory("ASCII");
+    private static final ArchiveStreamFactory FACTORY_SET_UTF8 = getFactory("UTF-8");
+    private static final ArchiveStreamFactory FACTORY_SET_ASCII = getFactory("ASCII");
+
+    // Default encoding if none is provided (not even null)
+    // The test currently assumes that the output default is the same as the input default
+    private static final String ARJ_DEFAULT;
+    private static final String DUMP_DEFAULT;
+
+    private static final String ZIP_DEFAULT = getField(new ZipArchiveInputStream(null),"encoding");
+    private static final String CPIO_DEFAULT = getField(new CpioArchiveInputStream(null),"encoding");
+    private static final String TAR_DEFAULT = getField(new TarArchiveInputStream(null),"encoding");
+    private static final String JAR_DEFAULT = getField(new JarArchiveInputStream(null),"encoding");
+
+    static {
+        String dflt;
+        dflt = "??";
+        try {
+            dflt = getField(new ArjArchiveInputStream(new FileInputStream(getFile("bla.arj"))), "charsetName");
+        } catch (ArchiveException e) {
+            e.printStackTrace();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        ARJ_DEFAULT = dflt;
+        dflt = "??";
+        try {
+            dflt = getField(new DumpArchiveInputStream(new FileInputStream(getFile("bla.dump"))), "encoding");
+        } catch (ArchiveException e) {
+            e.printStackTrace();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        DUMP_DEFAULT = dflt;
+    }
+
+    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"),
+        new TestData("bla.arj", ArchiveStreamFactory.ARJ, false, "ASCII", FACTORY_ASCII, "charsetName"),
+        new TestData("bla.arj", ArchiveStreamFactory.ARJ, false, "UTF-8", FACTORY_SET_UTF8, "charsetName"),
+        new TestData("bla.arj", ArchiveStreamFactory.ARJ, false, "ASCII", FACTORY_SET_ASCII, "charsetName"),
+
+        new TestData("bla.cpio", ArchiveStreamFactory.CPIO, true, CPIO_DEFAULT, FACTORY, "encoding"),
+        new TestData("bla.cpio", ArchiveStreamFactory.CPIO, true, "UTF-8", FACTORY_UTF8, "encoding"),
+        new TestData("bla.cpio", ArchiveStreamFactory.CPIO, true, "ASCII", FACTORY_ASCII, "encoding"),
+        new TestData("bla.cpio", ArchiveStreamFactory.CPIO, true, "UTF-8", FACTORY_SET_UTF8, "encoding"),
+        new TestData("bla.cpio", ArchiveStreamFactory.CPIO, true, "ASCII", FACTORY_SET_ASCII, "encoding"),
+
+        new TestData("bla.dump", ArchiveStreamFactory.DUMP, false, DUMP_DEFAULT, FACTORY, "encoding"),
+        new TestData("bla.dump", ArchiveStreamFactory.DUMP, false, "UTF-8", FACTORY_UTF8, "encoding"),
+        new TestData("bla.dump", ArchiveStreamFactory.DUMP, false, "ASCII", FACTORY_ASCII, "encoding"),
+        new TestData("bla.dump", ArchiveStreamFactory.DUMP, false, "UTF-8", FACTORY_SET_UTF8, "encoding"),
+        new TestData("bla.dump", ArchiveStreamFactory.DUMP, false, "ASCII", FACTORY_SET_ASCII, "encoding"),
+
+        new TestData("bla.tar", ArchiveStreamFactory.TAR, true, TAR_DEFAULT, FACTORY, "encoding"),
+        new TestData("bla.tar", ArchiveStreamFactory.TAR, true, "UTF-8", FACTORY_UTF8, "encoding"),
+        new TestData("bla.tar", ArchiveStreamFactory.TAR, true, "ASCII", FACTORY_ASCII, "encoding"),
+        new TestData("bla.tar", ArchiveStreamFactory.TAR, true, "UTF-8", FACTORY_SET_UTF8, "encoding"),
+        new TestData("bla.tar", ArchiveStreamFactory.TAR, true, "ASCII", FACTORY_SET_ASCII, "encoding"),
+
+        new TestData("bla.jar", ArchiveStreamFactory.JAR, true, JAR_DEFAULT, FACTORY, "encoding"),
+        new TestData("bla.jar", ArchiveStreamFactory.JAR, true, "UTF-8", FACTORY_UTF8, "encoding"),
+        new TestData("bla.jar", ArchiveStreamFactory.JAR, true, "ASCII", FACTORY_ASCII, "encoding"),
+        new TestData("bla.jar", ArchiveStreamFactory.JAR, true, "UTF-8", FACTORY_SET_UTF8, "encoding"),
+        new TestData("bla.jar", ArchiveStreamFactory.JAR, true, "ASCII", FACTORY_SET_ASCII, "encoding"),
+
+        new TestData("bla.zip", ArchiveStreamFactory.ZIP, true, ZIP_DEFAULT, FACTORY, "encoding"),
+        new TestData("bla.zip", ArchiveStreamFactory.ZIP, true, "UTF-8", FACTORY_UTF8, "encoding"),
+        new TestData("bla.zip", ArchiveStreamFactory.ZIP, true, "ASCII", FACTORY_ASCII, "encoding"),
+        new TestData("bla.zip", ArchiveStreamFactory.ZIP, true, "UTF-8", FACTORY_SET_UTF8, "encoding"),
+        new TestData("bla.zip", ArchiveStreamFactory.ZIP, true, "ASCII", FACTORY_SET_ASCII, "encoding"),
+    };
+
+    @Test
+    public void testEncodingInputStreamAutodetect() throws Exception {
+        int failed = 0;
+        for(int i = 1; i <= TESTS.length; i++) {
+            TestData test = TESTS[i-1];
+            ArchiveInputStream ais = getInputStreamFor(test.testFile, test.fac);
+            final String field = getField(ais,test.fieldName);
+            if (!eq(test.expectedEncoding,field)) {
+                System.out.println("Failed test " + i + ". expected: " + test.expectedEncoding + " actual: " + field + " type: " + test.type);
+                failed++;
+            }
+        }
+        if (failed > 0) {
+            fail("Tests failed: " + failed);
+        }
+    }
+
+    @Test
+    public void testEncodingInputStream() throws Exception {
+        int failed = 0;
+        for(int i = 1; i <= TESTS.length; i++) {
+            TestData test = TESTS[i-1];
+            ArchiveInputStream ais = getInputStreamFor(test.type, test.testFile, test.fac);
+            final String field = getField(ais,test.fieldName);
+            if (!eq(test.expectedEncoding,field)) {
+                System.out.println("Failed test " + i + ". expected: " + test.expectedEncoding + " actual: " + field + " type: " + test.type);
+                failed++;
+            }
+        }
+        if (failed > 0) {
+            fail("Tests failed: " + failed);
+        }
+    }
+
+    @Test
+    public void testEncodingOutputStream() throws Exception {
+        int failed = 0;
+        for(int i = 1; i <= TESTS.length; i++) {
+            TestData test = TESTS[i-1];
+            if (test.hasOutputStream) {
+                ArchiveOutputStream ais = getOutputStreamFor(test.type, test.fac);
+                final String field = getField(ais, test.fieldName);
+                if (!eq(test.expectedEncoding, field)) {
+                    System.out.println("Failed test " + i + ". expected: " + test.expectedEncoding + " actual: " + field + " type: " + test.type);
+                    failed++;
+                }
+            }
+        }
+        if (failed > 0) {
+            fail("Tests failed: " + failed);
+        }
+    }
+
+    // equals allowing null
+    private static boolean eq(String exp, String act) {
+        if (exp == null) {
+            return act == null;
+        }
+        return exp.equals(act);
+    }
+
+    private static String getField(Object instance, String name) {
+        Class<?> cls = instance.getClass();
+        Field fld;
+        try {
+            fld = cls.getDeclaredField(name);
+        } catch (NoSuchFieldException nsfe) {
+                try {
+                    fld = cls.getSuperclass().getDeclaredField(name);
+                } catch (NoSuchFieldException e) {
+                    System.out.println("Cannot find " + name + " in class " + instance.getClass().getSimpleName());
+                    return "??";
+                }                
+        }
+        boolean isAccessible = fld.isAccessible();
+        try {
+            if (!isAccessible) {
+                fld.setAccessible(true);
+            }
+            final Object object = fld.get(instance);
+            if (object instanceof String || object == null) {
+                return (String) object;
+            } else {
+                System.out.println("Wrong type: " + object.getClass().getCanonicalName() + " for " + name + " in class " + instance.getClass().getSimpleName());
+                return "??";                
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            return "??";
+        } finally {
+            if (!isAccessible) {
+                fld.setAccessible(isAccessible);
+            }
+        }
+    }
+
+    private ArchiveInputStream getInputStreamFor(String resource, ArchiveStreamFactory factory)
+            throws IOException, ArchiveException {
+        return factory.createArchiveInputStream(
+                   new BufferedInputStream(new FileInputStream(
+                       getFile(resource))));
+    }
+
+    private ArchiveInputStream getInputStreamFor(String type, String resource, ArchiveStreamFactory factory)
+            throws IOException, ArchiveException {
+        return factory.createArchiveInputStream(
+                   type,
+                   new BufferedInputStream(new FileInputStream(
+                       getFile(resource))));
+    }
+
+    private ArchiveOutputStream getOutputStreamFor(String type, ArchiveStreamFactory factory)
+            throws IOException, ArchiveException {
+        return factory.createArchiveOutputStream(type, new ByteArrayOutputStream());
+    }
 }