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 java.io.File;
22  import java.io.FileInputStream;
23  import java.io.FileOutputStream;
24  import java.io.IOException;
25  import java.io.InputStream;
26  import java.io.OutputStream;
27  import java.util.ArrayList;
28  import java.util.List;
29  
30  import org.apache.commons.compress.AbstractTestCase;
31  import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
32  import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
33  import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
34  import org.apache.commons.compress.archivers.zip.ZipFile;
35  import org.apache.commons.compress.archivers.zip.ZipMethod;
36  import org.apache.commons.compress.utils.IOUtils;
37  
38  public final class ZipTestCase extends AbstractTestCase {
39      /**
40       * Archives 2 files and unarchives it again. If the file length of result
41       * and source is the same, it looks like the operations have worked
42       * @throws Exception
43       */
44      public void testZipArchiveCreation() throws Exception {
45          // Archive
46          final File output = new File(dir, "bla.zip");
47          final File file1 = getFile("test1.xml");
48          final File file2 = getFile("test2.xml");
49  
50          final OutputStream out = new FileOutputStream(output);
51          ArchiveOutputStream os = null;
52          try {
53              os = new ArchiveStreamFactory()
54                  .createArchiveOutputStream("zip", out);
55              os.putArchiveEntry(new ZipArchiveEntry("testdata/test1.xml"));
56              IOUtils.copy(new FileInputStream(file1), os);
57              os.closeArchiveEntry();
58  
59              os.putArchiveEntry(new ZipArchiveEntry("testdata/test2.xml"));
60              IOUtils.copy(new FileInputStream(file2), os);
61              os.closeArchiveEntry();
62          } finally {
63              if (os != null) {
64                  os.close();
65              }
66          }
67          out.close();
68  
69          // Unarchive the same
70          List<File> results = new ArrayList<File>();
71  
72          final InputStream is = new FileInputStream(output);
73          ArchiveInputStream in = null;
74          try {
75              in = new ArchiveStreamFactory()
76                  .createArchiveInputStream("zip", is);
77  
78              ZipArchiveEntry entry = null;
79              while((entry = (ZipArchiveEntry)in.getNextEntry()) != null) {
80                  File outfile = new File(resultDir.getCanonicalPath() + "/result/" + entry.getName());
81                  outfile.getParentFile().mkdirs();
82                  OutputStream o = new FileOutputStream(outfile);
83                  try {
84                      IOUtils.copy(in, o);
85                  } finally {
86                      o.close();
87                  }
88                  results.add(outfile);
89              }
90          } finally {
91              if (in != null) {
92                  in.close();
93              }
94          }
95          is.close();
96  
97          assertEquals(results.size(), 2);
98          File result = results.get(0);
99          assertEquals(file1.length(), result.length());
100         result = results.get(1);
101         assertEquals(file2.length(), result.length());
102     }
103 
104     /**
105      * Simple unarchive test. Asserts nothing.
106      * @throws Exception
107      */
108     public void testZipUnarchive() throws Exception {
109         final File input = getFile("bla.zip");
110         final InputStream is = new FileInputStream(input);
111         final ArchiveInputStream in = new ArchiveStreamFactory().createArchiveInputStream("zip", is);
112         final ZipArchiveEntry entry = (ZipArchiveEntry)in.getNextEntry();
113         final OutputStream out = new FileOutputStream(new File(dir, entry.getName()));
114         IOUtils.copy(in, out);
115         out.close();
116         in.close();
117     }
118 
119     /**
120      * Test case for 
121      * <a href="https://issues.apache.org/jira/browse/COMPRESS-208"
122      * >COMPRESS-208</a>.
123      */
124     public void testSkipsPK00Prefix() throws Exception {
125         final File input = getFile("COMPRESS-208.zip");
126         InputStream is = new FileInputStream(input);
127         ArrayList<String> al = new ArrayList<String>();
128         al.add("test1.xml");
129         al.add("test2.xml");
130         try {
131             checkArchiveContent(new ZipArchiveInputStream(is), al);
132         } finally {
133             is.close();
134         }
135     }
136 
137     /**
138      * Test case for
139      * <a href="https://issues.apache.org/jira/browse/COMPRESS-93"
140      * >COMPRESS-93</a>.
141      */
142     public void testSupportedCompressionMethod() throws IOException {
143         /*
144         ZipFile bla = new ZipFile(getFile("bla.zip"));
145         assertTrue(bla.canReadEntryData(bla.getEntry("test1.xml")));
146         bla.close();
147         */
148         
149         ZipFile moby = new ZipFile(getFile("moby.zip"));
150         ZipArchiveEntry entry = moby.getEntry("README");
151         assertEquals("method", ZipMethod.TOKENIZATION.getCode(), entry.getMethod());
152         assertFalse(moby.canReadEntryData(entry));
153         moby.close();
154     }
155 
156     /**
157      * Test case for being able to skip an entry in an 
158      * {@link ZipArchiveInputStream} even if the compression method of that
159      * entry is unsupported.
160      *
161      * @see <a href="https://issues.apache.org/jira/browse/COMPRESS-93"
162      *        >COMPRESS-93</a>
163      */
164     public void testSkipEntryWithUnsupportedCompressionMethod()
165             throws IOException {
166         ZipArchiveInputStream zip =
167             new ZipArchiveInputStream(new FileInputStream(getFile("moby.zip")));
168         try {
169             ZipArchiveEntry entry = zip.getNextZipEntry();
170             assertEquals("method", ZipMethod.TOKENIZATION.getCode(), entry.getMethod());
171             assertEquals("README", entry.getName());
172             assertFalse(zip.canReadEntryData(entry));
173             try {
174                 assertNull(zip.getNextZipEntry());
175             } catch (IOException e) {
176                 e.printStackTrace();
177                 fail("COMPRESS-93: Unable to skip an unsupported zip entry");
178             }
179         } finally {
180             zip.close();
181         }
182     }
183 
184     /**
185      * Checks if all entries from a nested archive can be read.
186      * The archive: OSX_ArchiveWithNestedArchive.zip contains:
187      * NestedArchiv.zip and test.xml3.
188      * 
189      * The nested archive:  NestedArchive.zip contains test1.xml and test2.xml
190      * 
191      * @throws Exception
192      */
193     public void testListAllFilesWithNestedArchive() throws Exception {
194         final File input = getFile("OSX_ArchiveWithNestedArchive.zip");
195 
196         List<String> results = new ArrayList<String>();
197 
198         final InputStream is = new FileInputStream(input);
199         ArchiveInputStream in = null;
200         try {
201             in = new ArchiveStreamFactory().createArchiveInputStream("zip", is);
202 
203             ZipArchiveEntry entry = null;
204             while((entry = (ZipArchiveEntry)in.getNextEntry()) != null) {
205                 results.add(entry.getName());
206 
207                 ArchiveInputStream nestedIn = new ArchiveStreamFactory().createArchiveInputStream("zip", in);
208                 ZipArchiveEntry nestedEntry = null;
209                 while((nestedEntry = (ZipArchiveEntry)nestedIn.getNextEntry()) != null) {
210                     results.add(nestedEntry.getName());
211                 }
212                // nested stream must not be closed here
213             }
214         } finally {
215             if (in != null) {
216                 in.close();
217             }
218         }
219         is.close();
220 
221         results.contains("NestedArchiv.zip");
222         results.contains("test1.xml");
223         results.contains("test2.xml");
224         results.contains("test3.xml");
225     }
226 
227     public void testDirectoryEntryFromFile() throws Exception {
228         File[] tmp = createTempDirAndFile();
229         File archive = null;
230         ZipArchiveOutputStream zos = null;
231         ZipFile zf = null;
232         try {
233             archive = File.createTempFile("test.", ".zip", tmp[0]);
234             archive.deleteOnExit();
235             zos = new ZipArchiveOutputStream(archive);
236             long beforeArchiveWrite = tmp[0].lastModified();
237             ZipArchiveEntry in = new ZipArchiveEntry(tmp[0], "foo");
238             zos.putArchiveEntry(in);
239             zos.closeArchiveEntry();
240             zos.close();
241             zos = null;
242             zf = new ZipFile(archive);
243             ZipArchiveEntry out = zf.getEntry("foo/");
244             assertNotNull(out);
245             assertEquals("foo/", out.getName());
246             assertEquals(0, out.getSize());
247             // ZIP stores time with a granularity of 2 seconds
248             assertEquals(beforeArchiveWrite / 2000,
249                          out.getLastModifiedDate().getTime() / 2000);
250             assertTrue(out.isDirectory());
251         } finally {
252             ZipFile.closeQuietly(zf);
253             if (zos != null) {
254                 zos.close();
255             }
256             tryHardToDelete(archive);
257             tryHardToDelete(tmp[1]);
258             rmdir(tmp[0]);
259         }
260     }
261 
262     public void testExplicitDirectoryEntry() throws Exception {
263         File[] tmp = createTempDirAndFile();
264         File archive = null;
265         ZipArchiveOutputStream zos = null;
266         ZipFile zf = null;
267         try {
268             archive = File.createTempFile("test.", ".zip", tmp[0]);
269             archive.deleteOnExit();
270             zos = new ZipArchiveOutputStream(archive);
271             long beforeArchiveWrite = tmp[0].lastModified();
272             ZipArchiveEntry in = new ZipArchiveEntry("foo/");
273             in.setTime(beforeArchiveWrite);
274             zos.putArchiveEntry(in);
275             zos.closeArchiveEntry();
276             zos.close();
277             zos = null;
278             zf = new ZipFile(archive);
279             ZipArchiveEntry out = zf.getEntry("foo/");
280             assertNotNull(out);
281             assertEquals("foo/", out.getName());
282             assertEquals(0, out.getSize());
283             assertEquals(beforeArchiveWrite / 2000,
284                          out.getLastModifiedDate().getTime() / 2000);
285             assertTrue(out.isDirectory());
286         } finally {
287             ZipFile.closeQuietly(zf);
288             if (zos != null) {
289                 zos.close();
290             }
291             tryHardToDelete(archive);
292             tryHardToDelete(tmp[1]);
293             rmdir(tmp[0]);
294         }
295     }
296 
297     public void testFileEntryFromFile() throws Exception {
298         File[] tmp = createTempDirAndFile();
299         File archive = null;
300         ZipArchiveOutputStream zos = null;
301         ZipFile zf = null;
302         FileInputStream fis = null;
303         try {
304             archive = File.createTempFile("test.", ".zip", tmp[0]);
305             archive.deleteOnExit();
306             zos = new ZipArchiveOutputStream(archive);
307             ZipArchiveEntry in = new ZipArchiveEntry(tmp[1], "foo");
308             zos.putArchiveEntry(in);
309             byte[] b = new byte[(int) tmp[1].length()];
310             fis = new FileInputStream(tmp[1]);
311             while (fis.read(b) > 0) {
312                 zos.write(b);
313             }
314             fis.close();
315             fis = null;
316             zos.closeArchiveEntry();
317             zos.close();
318             zos = null;
319             zf = new ZipFile(archive);
320             ZipArchiveEntry out = zf.getEntry("foo");
321             assertNotNull(out);
322             assertEquals("foo", out.getName());
323             assertEquals(tmp[1].length(), out.getSize());
324             assertEquals(tmp[1].lastModified() / 2000,
325                          out.getLastModifiedDate().getTime() / 2000);
326             assertFalse(out.isDirectory());
327         } finally {
328             ZipFile.closeQuietly(zf);
329             if (zos != null) {
330                 zos.close();
331             }
332             tryHardToDelete(archive);
333             if (fis != null) {
334                 fis.close();
335             }
336             tryHardToDelete(tmp[1]);
337             rmdir(tmp[0]);
338         }
339     }
340 
341     public void testExplicitFileEntry() throws Exception {
342         File[] tmp = createTempDirAndFile();
343         File archive = null;
344         ZipArchiveOutputStream zos = null;
345         ZipFile zf = null;
346         FileInputStream fis = null;
347         try {
348             archive = File.createTempFile("test.", ".zip", tmp[0]);
349             archive.deleteOnExit();
350             zos = new ZipArchiveOutputStream(archive);
351             ZipArchiveEntry in = new ZipArchiveEntry("foo");
352             in.setTime(tmp[1].lastModified());
353             in.setSize(tmp[1].length());
354             zos.putArchiveEntry(in);
355             byte[] b = new byte[(int) tmp[1].length()];
356             fis = new FileInputStream(tmp[1]);
357             while (fis.read(b) > 0) {
358                 zos.write(b);
359             }
360             fis.close();
361             fis = null;
362             zos.closeArchiveEntry();
363             zos.close();
364             zos = null;
365             zf = new ZipFile(archive);
366             ZipArchiveEntry out = zf.getEntry("foo");
367             assertNotNull(out);
368             assertEquals("foo", out.getName());
369             assertEquals(tmp[1].length(), out.getSize());
370             assertEquals(tmp[1].lastModified() / 2000,
371                          out.getLastModifiedDate().getTime() / 2000);
372             assertFalse(out.isDirectory());
373         } finally {
374             ZipFile.closeQuietly(zf);
375             if (zos != null) {
376                 zos.close();
377             }
378             tryHardToDelete(archive);
379             if (fis != null) {
380                 fis.close();
381             }
382             tryHardToDelete(tmp[1]);
383             rmdir(tmp[0]);
384         }
385     }
386 }