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