View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.commons.compress.archivers;
20  
21  import static org.apache.commons.compress.AbstractTestCase.getFile;
22  import static org.junit.Assert.assertEquals;
23  import static org.junit.Assert.assertNull;
24  import static org.junit.Assert.assertTrue;
25  import static org.junit.Assert.fail;
26  
27  import java.io.BufferedInputStream;
28  import java.io.ByteArrayInputStream;
29  import java.io.ByteArrayOutputStream;
30  import java.io.FileInputStream;
31  import java.io.IOException;
32  import java.io.InputStream;
33  import java.lang.reflect.Field;
34  
35  import org.apache.commons.compress.archivers.arj.ArjArchiveInputStream;
36  import org.apache.commons.compress.archivers.cpio.CpioArchiveInputStream;
37  import org.apache.commons.compress.archivers.dump.DumpArchiveInputStream;
38  import org.apache.commons.compress.archivers.jar.JarArchiveInputStream;
39  import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
40  import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
41  import org.junit.Test;
42  
43  public class ArchiveStreamFactoryTest {
44  
45      private static final String UNKNOWN = "??";
46  
47      /**
48       * see https://issues.apache.org/jira/browse/COMPRESS-171
49       */
50      @Test
51      public void shortTextFilesAreNoTARs() throws Exception {
52          try {
53              new ArchiveStreamFactory()
54                  .createArchiveInputStream(new ByteArrayInputStream("This certainly is not a tar archive, really, no kidding".getBytes()));
55              fail("created an input stream for a non-archive");
56          } catch (final ArchiveException ae) {
57              assertTrue(ae.getMessage().startsWith("No Archiver found"));
58          }
59      }
60  
61      /**
62       * see https://issues.apache.org/jira/browse/COMPRESS-191
63       */
64      @Test
65      public void aiffFilesAreNoTARs() throws Exception {
66      	final FileInputStream fis = new FileInputStream("src/test/resources/testAIFF.aif");
67      	try {
68              final InputStream is = new BufferedInputStream(fis);
69              try {
70                  new ArchiveStreamFactory().createArchiveInputStream(is);
71                  fail("created an input stream for a non-archive");
72              } catch (final ArchiveException ae) {
73                  assertTrue(ae.getMessage().startsWith("No Archiver found"));
74              } finally {
75                  is.close();
76              }
77      	} finally {
78              fis.close();
79      	}
80      }
81  
82      @Test
83      public void testCOMPRESS209() throws Exception {
84      	final FileInputStream fis = new FileInputStream("src/test/resources/testCompress209.doc");
85      	try {
86              final InputStream bis = new BufferedInputStream(fis);
87              try {
88                  new ArchiveStreamFactory().createArchiveInputStream(bis);
89                  fail("created an input stream for a non-archive");
90              } catch (final ArchiveException ae) {
91                  assertTrue(ae.getMessage().startsWith("No Archiver found"));
92              } finally {
93                  bis.close();
94              }
95      	} finally {
96              fis.close();
97      	}
98      }
99  
100     @Test(expected = StreamingNotSupportedException.class)
101     public void cantRead7zFromStream() throws Exception {
102         new ArchiveStreamFactory()
103             .createArchiveInputStream(ArchiveStreamFactory.SEVEN_Z,
104                                       new ByteArrayInputStream(new byte[0]));
105     }
106 
107     @Test(expected = StreamingNotSupportedException.class)
108     public void cantWrite7zToStream() throws Exception {
109         new ArchiveStreamFactory()
110             .createArchiveOutputStream(ArchiveStreamFactory.SEVEN_Z,
111                                        new ByteArrayOutputStream());
112     }
113 
114     /**
115      * Test case for 
116      * <a href="https://issues.apache.org/jira/browse/COMPRESS-267"
117      * >COMPRESS-267</a>.
118      */
119     @Test
120     public void detectsAndThrowsFor7z() throws Exception {
121     	final FileInputStream fis = new FileInputStream("src/test/resources/bla.7z");
122     	try {
123             final InputStream bis = new BufferedInputStream(fis);
124             try {
125                 new ArchiveStreamFactory().createArchiveInputStream(bis);
126                 fail("Expected a StreamingNotSupportedException");
127             } catch (final StreamingNotSupportedException ex) {
128                 assertEquals(ArchiveStreamFactory.SEVEN_Z, ex.getFormat());
129             } finally {
130                 bis.close();
131             }
132     	} finally {
133             fis.close();
134     	}
135     }
136 
137     /**
138      * Test case for 
139      * <a href="https://issues.apache.org/jira/browse/COMPRESS-208"
140      * >COMPRESS-208</a>.
141      */
142     @Test
143     public void skipsPK00Prefix() throws Exception {
144     	final FileInputStream fis = new FileInputStream("src/test/resources/COMPRESS-208.zip");
145     	try {
146             final InputStream bis = new BufferedInputStream(fis);
147             try {
148                 final ArchiveInputStream ais = new ArchiveStreamFactory().createArchiveInputStream(bis);
149                 try {
150                     assertTrue(ais instanceof ZipArchiveInputStream);
151                 } finally {
152                     ais.close();
153                 }
154             } finally {
155                 bis.close();
156             }
157     	} finally {
158             fis.close();
159     	}
160     }
161     
162     @Test
163     public void testEncodingCtor() {
164         ArchiveStreamFactory fac = new ArchiveStreamFactory();
165         assertNull(fac.getEntryEncoding());
166         fac = new ArchiveStreamFactory(null);
167         assertNull(fac.getEntryEncoding());
168         fac = new ArchiveStreamFactory("UTF-8");
169         assertEquals("UTF-8", fac.getEntryEncoding());
170     }
171 
172     @Test
173     @SuppressWarnings("deprecation")
174     public void testEncodingDeprecated() {
175         ArchiveStreamFactory fac = new ArchiveStreamFactory();
176         assertNull(fac.getEntryEncoding());
177         fac.setEntryEncoding("UTF-8");
178         assertEquals("UTF-8", fac.getEntryEncoding());
179         fac.setEntryEncoding("US_ASCII");
180         assertEquals("US_ASCII", fac.getEntryEncoding());
181         fac = new ArchiveStreamFactory("UTF-8");
182         assertEquals("UTF-8", fac.getEntryEncoding());
183         try {
184             fac.setEntryEncoding("US_ASCII");
185             fail("Expected IllegalStateException");
186         } catch (final IllegalStateException ise) {
187             // expected
188         }
189     }
190 
191     static class TestData {
192         final String testFile;
193         final String expectedEncoding;
194         final ArchiveStreamFactory fac;
195         final String fieldName;
196         final String type;
197         final boolean hasOutputStream;
198         TestData(final String testFile, final String type, final boolean hasOut, final String expectedEncoding, final ArchiveStreamFactory fac, final String fieldName) {
199             this.testFile = testFile;
200             this.expectedEncoding = expectedEncoding;
201             this.fac = fac;
202             this.fieldName = fieldName;
203             this.type = type;
204             this.hasOutputStream = hasOut;
205         }
206     }
207 
208     @SuppressWarnings("deprecation") // test of deprecated method
209     static ArchiveStreamFactory getFactory(final String entryEncoding) {
210         final ArchiveStreamFactory fac = new ArchiveStreamFactory();
211         fac.setEntryEncoding(entryEncoding);
212         return fac;
213     }
214     // The different factory types
215     private static final ArchiveStreamFactory FACTORY = new ArchiveStreamFactory();
216     private static final ArchiveStreamFactory FACTORY_UTF8 = new ArchiveStreamFactory("UTF-8");
217     private static final ArchiveStreamFactory FACTORY_ASCII = new ArchiveStreamFactory("ASCII");
218     private static final ArchiveStreamFactory FACTORY_SET_UTF8 = getFactory("UTF-8");
219     private static final ArchiveStreamFactory FACTORY_SET_ASCII = getFactory("ASCII");
220 
221     // Default encoding if none is provided (not even null)
222     // The test currently assumes that the output default is the same as the input default
223     private static final String ARJ_DEFAULT;
224     private static final String DUMP_DEFAULT;
225 
226     private static final String ZIP_DEFAULT = getField(new ZipArchiveInputStream(null),"encoding");
227     private static final String CPIO_DEFAULT = getField(new CpioArchiveInputStream(null),"encoding");
228     private static final String TAR_DEFAULT = getField(new TarArchiveInputStream(null),"encoding");
229     private static final String JAR_DEFAULT = getField(new JarArchiveInputStream(null),"encoding");
230 
231     static {
232         String dflt;
233         dflt = UNKNOWN;
234         try {
235             dflt = getField(new ArjArchiveInputStream(new FileInputStream(getFile("bla.arj"))), "charsetName");
236         } catch (final ArchiveException e) {
237             e.printStackTrace();
238         } catch (final Exception e) {
239             e.printStackTrace();
240         }
241         ARJ_DEFAULT = dflt;
242         dflt = UNKNOWN;
243         try {
244             dflt = getField(new DumpArchiveInputStream(new FileInputStream(getFile("bla.dump"))), "encoding");
245         } catch (final ArchiveException e) {
246             e.printStackTrace();
247         } catch (final Exception e) {
248             e.printStackTrace();
249         }
250         DUMP_DEFAULT = dflt;
251     }
252 
253     static final TestData[] TESTS = {
254         new TestData("bla.arj", ArchiveStreamFactory.ARJ, false, ARJ_DEFAULT, FACTORY, "charsetName"),
255         new TestData("bla.arj", ArchiveStreamFactory.ARJ, false, "UTF-8", FACTORY_UTF8, "charsetName"),
256         new TestData("bla.arj", ArchiveStreamFactory.ARJ, false, "ASCII", FACTORY_ASCII, "charsetName"),
257         new TestData("bla.arj", ArchiveStreamFactory.ARJ, false, "UTF-8", FACTORY_SET_UTF8, "charsetName"),
258         new TestData("bla.arj", ArchiveStreamFactory.ARJ, false, "ASCII", FACTORY_SET_ASCII, "charsetName"),
259 
260         new TestData("bla.cpio", ArchiveStreamFactory.CPIO, true, CPIO_DEFAULT, FACTORY, "encoding"),
261         new TestData("bla.cpio", ArchiveStreamFactory.CPIO, true, "UTF-8", FACTORY_UTF8, "encoding"),
262         new TestData("bla.cpio", ArchiveStreamFactory.CPIO, true, "ASCII", FACTORY_ASCII, "encoding"),
263         new TestData("bla.cpio", ArchiveStreamFactory.CPIO, true, "UTF-8", FACTORY_SET_UTF8, "encoding"),
264         new TestData("bla.cpio", ArchiveStreamFactory.CPIO, true, "ASCII", FACTORY_SET_ASCII, "encoding"),
265 
266         new TestData("bla.dump", ArchiveStreamFactory.DUMP, false, DUMP_DEFAULT, FACTORY, "encoding"),
267         new TestData("bla.dump", ArchiveStreamFactory.DUMP, false, "UTF-8", FACTORY_UTF8, "encoding"),
268         new TestData("bla.dump", ArchiveStreamFactory.DUMP, false, "ASCII", FACTORY_ASCII, "encoding"),
269         new TestData("bla.dump", ArchiveStreamFactory.DUMP, false, "UTF-8", FACTORY_SET_UTF8, "encoding"),
270         new TestData("bla.dump", ArchiveStreamFactory.DUMP, false, "ASCII", FACTORY_SET_ASCII, "encoding"),
271 
272         new TestData("bla.tar", ArchiveStreamFactory.TAR, true, TAR_DEFAULT, FACTORY, "encoding"),
273         new TestData("bla.tar", ArchiveStreamFactory.TAR, true, "UTF-8", FACTORY_UTF8, "encoding"),
274         new TestData("bla.tar", ArchiveStreamFactory.TAR, true, "ASCII", FACTORY_ASCII, "encoding"),
275         new TestData("bla.tar", ArchiveStreamFactory.TAR, true, "UTF-8", FACTORY_SET_UTF8, "encoding"),
276         new TestData("bla.tar", ArchiveStreamFactory.TAR, true, "ASCII", FACTORY_SET_ASCII, "encoding"),
277 
278         new TestData("bla.jar", ArchiveStreamFactory.JAR, true, JAR_DEFAULT, FACTORY, "encoding"),
279         new TestData("bla.jar", ArchiveStreamFactory.JAR, true, "UTF-8", FACTORY_UTF8, "encoding"),
280         new TestData("bla.jar", ArchiveStreamFactory.JAR, true, "ASCII", FACTORY_ASCII, "encoding"),
281         new TestData("bla.jar", ArchiveStreamFactory.JAR, true, "UTF-8", FACTORY_SET_UTF8, "encoding"),
282         new TestData("bla.jar", ArchiveStreamFactory.JAR, true, "ASCII", FACTORY_SET_ASCII, "encoding"),
283 
284         new TestData("bla.zip", ArchiveStreamFactory.ZIP, true, ZIP_DEFAULT, FACTORY, "encoding"),
285         new TestData("bla.zip", ArchiveStreamFactory.ZIP, true, "UTF-8", FACTORY_UTF8, "encoding"),
286         new TestData("bla.zip", ArchiveStreamFactory.ZIP, true, "ASCII", FACTORY_ASCII, "encoding"),
287         new TestData("bla.zip", ArchiveStreamFactory.ZIP, true, "UTF-8", FACTORY_SET_UTF8, "encoding"),
288         new TestData("bla.zip", ArchiveStreamFactory.ZIP, true, "ASCII", FACTORY_SET_ASCII, "encoding"),
289     };
290 
291     @Test
292     public void testEncodingInputStreamAutodetect() throws Exception {
293         int failed = 0;
294         for(int i = 1; i <= TESTS.length; i++) {
295             final TestData test = TESTS[i-1];
296             final ArchiveInputStream ais = getInputStreamFor(test.testFile, test.fac);
297             final String field = getField(ais,test.fieldName);
298             if (!eq(test.expectedEncoding,field)) {
299                 System.out.println("Failed test " + i + ". expected: " + test.expectedEncoding + " actual: " + field + " type: " + test.type);
300                 failed++;
301             }
302         }
303         if (failed > 0) {
304             fail("Tests failed: " + failed);
305         }
306     }
307 
308     @Test
309     public void testEncodingInputStream() throws Exception {
310         int failed = 0;
311         for(int i = 1; i <= TESTS.length; i++) {
312             final TestData test = TESTS[i-1];
313             final ArchiveInputStream ais = getInputStreamFor(test.type, test.testFile, test.fac);
314             final String field = getField(ais,test.fieldName);
315             if (!eq(test.expectedEncoding,field)) {
316                 System.out.println("Failed test " + i + ". expected: " + test.expectedEncoding + " actual: " + field + " type: " + test.type);
317                 failed++;
318             }
319         }
320         if (failed > 0) {
321             fail("Tests failed: " + failed);
322         }
323     }
324 
325     @Test
326     public void testEncodingOutputStream() throws Exception {
327         int failed = 0;
328         for(int i = 1; i <= TESTS.length; i++) {
329             final TestData test = TESTS[i-1];
330             if (test.hasOutputStream) {
331                 final ArchiveOutputStream ais = getOutputStreamFor(test.type, test.fac);
332                 final String field = getField(ais, test.fieldName);
333                 if (!eq(test.expectedEncoding, field)) {
334                     System.out.println("Failed test " + i + ". expected: " + test.expectedEncoding + " actual: " + field + " type: " + test.type);
335                     failed++;
336                 }
337             }
338         }
339         if (failed > 0) {
340             fail("Tests failed: " + failed);
341         }
342     }
343 
344     // equals allowing null
345     private static boolean eq(final String exp, final String act) {
346         if (exp == null) {
347             return act == null;
348         }
349         return exp.equals(act);
350     }
351 
352     private static String getField(final Object instance, final String name) {
353         final Class<?> cls = instance.getClass();
354         Field fld;
355         try {
356             fld = cls.getDeclaredField(name);
357         } catch (final NoSuchFieldException nsfe) {
358                 try {
359                     fld = cls.getSuperclass().getDeclaredField(name);
360                 } catch (final NoSuchFieldException e) {
361                     System.out.println("Cannot find " + name + " in class " + instance.getClass().getSimpleName());
362                     return UNKNOWN;
363                 }                
364         }
365         final boolean isAccessible = fld.isAccessible();
366         try {
367             if (!isAccessible) {
368                 fld.setAccessible(true);
369             }
370             final Object object = fld.get(instance);
371             if (object instanceof String || object == null) {
372                 return (String) object;
373             }
374             System.out.println("Wrong type: " + object.getClass().getCanonicalName() + " for " + name + " in class " + instance.getClass().getSimpleName());
375             return UNKNOWN;
376         } catch (final Exception e) {
377             e.printStackTrace();
378             return UNKNOWN;
379         } finally {
380             if (!isAccessible) {
381                 fld.setAccessible(isAccessible);
382             }
383         }
384     }
385 
386     private ArchiveInputStream getInputStreamFor(final String resource, final ArchiveStreamFactory factory)
387             throws IOException, ArchiveException {
388         return factory.createArchiveInputStream(
389                    new BufferedInputStream(new FileInputStream(
390                        getFile(resource))));
391     }
392 
393     private ArchiveInputStream getInputStreamFor(final String type, final String resource, final ArchiveStreamFactory factory)
394             throws IOException, ArchiveException {
395         return factory.createArchiveInputStream(
396                    type,
397                    new BufferedInputStream(new FileInputStream(
398                        getFile(resource))));
399     }
400 
401     private ArchiveOutputStream getOutputStreamFor(final String type, final ArchiveStreamFactory factory)
402             throws IOException, ArchiveException {
403         return factory.createArchiveOutputStream(type, new ByteArrayOutputStream());
404     }
405 }