View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one or more
3    *  contributor license agreements.  See the NOTICE file distributed with
4    *  this work for additional information regarding copyright ownership.
5    *  The ASF licenses this file to You under the Apache License, Version 2.0
6    *  (the "License"); you may not use this file except in compliance with
7    *  the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   *  Unless required by applicable law or agreed to in writing, software
12   *  distributed under the License is distributed on an "AS IS" BASIS,
13   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   *  See the License for the specific language governing permissions and
15   *  limitations under the License.
16   *
17   */
18  
19  package org.apache.commons.compress.archivers.zip;
20  
21  import static org.apache.commons.compress.AbstractTestCase.getFile;
22  import static org.junit.Assert.*;
23  
24  import java.io.File;
25  import java.io.FileInputStream;
26  import java.io.FileOutputStream;
27  import java.io.InputStream;
28  import java.io.OutputStream;
29  import java.util.ArrayList;
30  import java.util.Arrays;
31  import java.util.Collections;
32  import java.util.Enumeration;
33  import java.util.TreeMap;
34  import java.util.zip.ZipEntry;
35  
36  import org.apache.commons.compress.utils.IOUtils;
37  import org.apache.commons.compress.utils.SeekableInMemoryByteChannel;
38  import org.junit.After;
39  import org.junit.Test;
40  
41  public class ZipFileTest {
42      private ZipFile zf = null;
43  
44      @After
45      public void tearDown() {
46          ZipFile.closeQuietly(zf);
47      }
48  
49      @Test
50      public void testCDOrder() throws Exception {
51          readOrderTest();
52          final ArrayList<ZipArchiveEntry> l = Collections.list(zf.getEntries());
53          assertEntryName(l, 0, "AbstractUnicodeExtraField");
54          assertEntryName(l, 1, "AsiExtraField");
55          assertEntryName(l, 2, "ExtraFieldUtils");
56          assertEntryName(l, 3, "FallbackZipEncoding");
57          assertEntryName(l, 4, "GeneralPurposeBit");
58          assertEntryName(l, 5, "JarMarker");
59          assertEntryName(l, 6, "NioZipEncoding");
60          assertEntryName(l, 7, "Simple8BitZipEncoding");
61          assertEntryName(l, 8, "UnicodeCommentExtraField");
62          assertEntryName(l, 9, "UnicodePathExtraField");
63          assertEntryName(l, 10, "UnixStat");
64          assertEntryName(l, 11, "UnparseableExtraFieldData");
65          assertEntryName(l, 12, "UnrecognizedExtraField");
66          assertEntryName(l, 13, "ZipArchiveEntry");
67          assertEntryName(l, 14, "ZipArchiveInputStream");
68          assertEntryName(l, 15, "ZipArchiveOutputStream");
69          assertEntryName(l, 16, "ZipEncoding");
70          assertEntryName(l, 17, "ZipEncodingHelper");
71          assertEntryName(l, 18, "ZipExtraField");
72          assertEntryName(l, 19, "ZipUtil");
73          assertEntryName(l, 20, "ZipLong");
74          assertEntryName(l, 21, "ZipShort");
75          assertEntryName(l, 22, "ZipFile");
76      }
77  
78      @Test
79      public void testCDOrderInMemory() throws Exception {
80          byte[] data = null;
81          try (FileInputStream fis = new FileInputStream(getFile("ordertest.zip"))) {
82              data = IOUtils.toByteArray(fis);
83          }
84  
85          zf = new ZipFile(new SeekableInMemoryByteChannel(data), ZipEncodingHelper.UTF8);
86          final ArrayList<ZipArchiveEntry> l = Collections.list(zf.getEntries());
87          assertEntryName(l, 0, "AbstractUnicodeExtraField");
88          assertEntryName(l, 1, "AsiExtraField");
89          assertEntryName(l, 2, "ExtraFieldUtils");
90          assertEntryName(l, 3, "FallbackZipEncoding");
91          assertEntryName(l, 4, "GeneralPurposeBit");
92          assertEntryName(l, 5, "JarMarker");
93          assertEntryName(l, 6, "NioZipEncoding");
94          assertEntryName(l, 7, "Simple8BitZipEncoding");
95          assertEntryName(l, 8, "UnicodeCommentExtraField");
96          assertEntryName(l, 9, "UnicodePathExtraField");
97          assertEntryName(l, 10, "UnixStat");
98          assertEntryName(l, 11, "UnparseableExtraFieldData");
99          assertEntryName(l, 12, "UnrecognizedExtraField");
100         assertEntryName(l, 13, "ZipArchiveEntry");
101         assertEntryName(l, 14, "ZipArchiveInputStream");
102         assertEntryName(l, 15, "ZipArchiveOutputStream");
103         assertEntryName(l, 16, "ZipEncoding");
104         assertEntryName(l, 17, "ZipEncodingHelper");
105         assertEntryName(l, 18, "ZipExtraField");
106         assertEntryName(l, 19, "ZipUtil");
107         assertEntryName(l, 20, "ZipLong");
108         assertEntryName(l, 21, "ZipShort");
109         assertEntryName(l, 22, "ZipFile");
110     }
111 
112     @Test
113     public void testPhysicalOrder() throws Exception {
114         readOrderTest();
115         final ArrayList<ZipArchiveEntry> l = Collections.list(zf.getEntriesInPhysicalOrder());
116         assertEntryName(l, 0, "AbstractUnicodeExtraField");
117         assertEntryName(l, 1, "AsiExtraField");
118         assertEntryName(l, 2, "ExtraFieldUtils");
119         assertEntryName(l, 3, "FallbackZipEncoding");
120         assertEntryName(l, 4, "GeneralPurposeBit");
121         assertEntryName(l, 5, "JarMarker");
122         assertEntryName(l, 6, "NioZipEncoding");
123         assertEntryName(l, 7, "Simple8BitZipEncoding");
124         assertEntryName(l, 8, "UnicodeCommentExtraField");
125         assertEntryName(l, 9, "UnicodePathExtraField");
126         assertEntryName(l, 10, "UnixStat");
127         assertEntryName(l, 11, "UnparseableExtraFieldData");
128         assertEntryName(l, 12, "UnrecognizedExtraField");
129         assertEntryName(l, 13, "ZipArchiveEntry");
130         assertEntryName(l, 14, "ZipArchiveInputStream");
131         assertEntryName(l, 15, "ZipArchiveOutputStream");
132         assertEntryName(l, 16, "ZipEncoding");
133         assertEntryName(l, 17, "ZipEncodingHelper");
134         assertEntryName(l, 18, "ZipExtraField");
135         assertEntryName(l, 19, "ZipFile");
136         assertEntryName(l, 20, "ZipLong");
137         assertEntryName(l, 21, "ZipShort");
138         assertEntryName(l, 22, "ZipUtil");
139     }
140 
141     @Test
142     public void testDoubleClose() throws Exception {
143         readOrderTest();
144         zf.close();
145         try {
146             zf.close();
147         } catch (final Exception ex) {
148             fail("Caught exception of second close");
149         }
150     }
151 
152     @Test
153     public void testReadingOfStoredEntry() throws Exception {
154         final File f = File.createTempFile("commons-compress-zipfiletest", ".zip");
155         f.deleteOnExit();
156         OutputStream o = null;
157         InputStream i = null;
158         try {
159             o = new FileOutputStream(f);
160             final ZipArchiveOutputStream zo = new ZipArchiveOutputStream(o);
161             ZipArchiveEntry ze = new ZipArchiveEntry("foo");
162             ze.setMethod(ZipEntry.STORED);
163             ze.setSize(4);
164             ze.setCrc(0xb63cfbcdl);
165             zo.putArchiveEntry(ze);
166             zo.write(new byte[] { 1, 2, 3, 4 });
167             zo.closeArchiveEntry();
168             zo.close();
169             o.close();
170             o  = null;
171 
172             zf = new ZipFile(f);
173             ze = zf.getEntry("foo");
174             assertNotNull(ze);
175             i = zf.getInputStream(ze);
176             final byte[] b = new byte[4];
177             assertEquals(4, i.read(b));
178             assertEquals(-1, i.read());
179         } finally {
180             if (o != null) {
181                 o.close();
182             }
183             if (i != null) {
184                 i.close();
185             }
186             f.delete();
187         }
188     }
189 
190     /**
191      * @see "https://issues.apache.org/jira/browse/COMPRESS-176"
192      */
193     @Test
194     public void testWinzipBackSlashWorkaround() throws Exception {
195         final File archive = getFile("test-winzip.zip");
196         zf = new ZipFile(archive);
197         assertNull(zf.getEntry("\u00e4\\\u00fc.txt"));
198         assertNotNull(zf.getEntry("\u00e4/\u00fc.txt"));
199     }
200 
201     /**
202      * Test case for 
203      * <a href="https://issues.apache.org/jira/browse/COMPRESS-208"
204      * >COMPRESS-208</a>.
205      */
206     @Test
207     public void testSkipsPK00Prefix() throws Exception {
208         final File archive = getFile("COMPRESS-208.zip");
209         zf = new ZipFile(archive);
210         assertNotNull(zf.getEntry("test1.xml"));
211         assertNotNull(zf.getEntry("test2.xml"));
212     }
213 
214     @Test
215     public void testUnixSymlinkSampleFile() throws Exception {
216         final String entryPrefix = "COMPRESS-214_unix_symlinks/";
217         final TreeMap<String, String> expectedVals = new TreeMap<>();
218 
219         // I threw in some Japanese characters to keep things interesting.
220         expectedVals.put(entryPrefix + "link1", "../COMPRESS-214_unix_symlinks/./a/b/c/../../../\uF999");
221         expectedVals.put(entryPrefix + "link2", "../COMPRESS-214_unix_symlinks/./a/b/c/../../../g");
222         expectedVals.put(entryPrefix + "link3", "../COMPRESS-214_unix_symlinks/././a/b/c/../../../\u76F4\u6A39");
223         expectedVals.put(entryPrefix + "link4", "\u82B1\u5B50/\u745B\u5B50");
224         expectedVals.put(entryPrefix + "\uF999", "./\u82B1\u5B50/\u745B\u5B50/\u5897\u8C37/\uF999");
225         expectedVals.put(entryPrefix + "g", "./a/b/c/d/e/f/g");
226         expectedVals.put(entryPrefix + "\u76F4\u6A39", "./g");
227 
228         // Notice how a directory link might contain a trailing slash, or it might not.
229         // Also note:  symlinks are always stored as files, even if they link to directories.
230         expectedVals.put(entryPrefix + "link5", "../COMPRESS-214_unix_symlinks/././a/b");
231         expectedVals.put(entryPrefix + "link6", "../COMPRESS-214_unix_symlinks/././a/b/");
232 
233         // I looked into creating a test with hard links, but zip does not appear to
234         // support hard links, so nevermind.
235 
236         final File archive = getFile("COMPRESS-214_unix_symlinks.zip");
237 
238         zf = new ZipFile(archive);
239         final Enumeration<ZipArchiveEntry> en = zf.getEntries();
240         while (en.hasMoreElements()) {
241             final ZipArchiveEntry zae = en.nextElement();
242             final String link = zf.getUnixSymlink(zae);
243             if (zae.isUnixSymlink()) {
244                 final String name = zae.getName();
245                 final String expected = expectedVals.get(name);
246                 assertEquals(expected, link);
247             } else {
248                 // Should be null if it's not a symlink!
249                 assertNull(link);
250             }
251         }
252     }
253 
254     /**
255      * @see "https://issues.apache.org/jira/browse/COMPRESS-227"
256      */
257     @Test
258     public void testDuplicateEntry() throws Exception {
259         final File archive = getFile("COMPRESS-227.zip");
260         zf = new ZipFile(archive);
261 
262         final ZipArchiveEntry ze = zf.getEntry("test1.txt");
263         assertNotNull(ze);
264         assertNotNull(zf.getInputStream(ze));
265 
266         int numberOfEntries = 0;
267         for (final ZipArchiveEntry entry : zf.getEntries("test1.txt")) {
268             numberOfEntries++;
269             assertNotNull(zf.getInputStream(entry));
270         }
271         assertEquals(2, numberOfEntries);
272     }
273 
274     /**
275      * @see "https://issues.apache.org/jira/browse/COMPRESS-228"
276      */
277     @Test
278     public void testExcessDataInZip64ExtraField() throws Exception {
279         final File archive = getFile("COMPRESS-228.zip");
280         zf = new ZipFile(archive);
281         // actually, if we get here, the test already has passed
282 
283         final ZipArchiveEntry ze = zf.getEntry("src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java");
284         assertEquals(26101, ze.getSize());
285     }
286 
287     @Test
288     public void testUnshrinking() throws Exception {
289         zf = new ZipFile(getFile("SHRUNK.ZIP"));
290         ZipArchiveEntry test = zf.getEntry("TEST1.XML");
291         FileInputStream original = new FileInputStream(getFile("test1.xml"));
292         try {
293             assertArrayEquals(IOUtils.toByteArray(original),
294                               IOUtils.toByteArray(zf.getInputStream(test)));
295         } finally {
296             original.close();
297         }
298         test = zf.getEntry("TEST2.XML");
299         original = new FileInputStream(getFile("test2.xml"));
300         try {
301             assertArrayEquals(IOUtils.toByteArray(original),
302                               IOUtils.toByteArray(zf.getInputStream(test)));
303         } finally {
304             original.close();
305         }
306     }
307 
308     /**
309      * Test case for 
310      * <a href="https://issues.apache.org/jira/browse/COMPRESS-264"
311      * >COMPRESS-264</a>.
312      */
313     @Test
314     public void testReadingOfFirstStoredEntry() throws Exception {
315         final File archive = getFile("COMPRESS-264.zip");
316         zf = new ZipFile(archive);
317         final ZipArchiveEntry ze = zf.getEntry("test.txt");
318         assertEquals(5, ze.getSize());
319         assertArrayEquals(new byte[] {'d', 'a', 't', 'a', '\n'},
320                           IOUtils.toByteArray(zf.getInputStream(ze)));
321     }
322 
323     @Test
324     public void testUnzipBZip2CompressedEntry() throws Exception {
325         final File archive = getFile("bzip2-zip.zip");
326         zf = new ZipFile(archive);
327         final ZipArchiveEntry ze = zf.getEntry("lots-of-as");
328         assertEquals(42, ze.getSize());
329         final byte[] expected = new byte[42];
330         Arrays.fill(expected , (byte)'a');
331         assertArrayEquals(expected, IOUtils.toByteArray(zf.getInputStream(ze)));
332     }
333 
334     /*
335      * ordertest.zip has been handcrafted.
336      *
337      * It contains enough files so any random coincidence of
338      * entries.keySet() and central directory order would be unlikely
339      * - in fact testCDOrder fails in svn revision 920284.
340      *
341      * The central directory has ZipFile and ZipUtil swapped so
342      * central directory order is different from entry data order.
343      */
344     private void readOrderTest() throws Exception {
345         final File archive = getFile("ordertest.zip");
346         zf = new ZipFile(archive);
347     }
348 
349     private static void assertEntryName(final ArrayList<ZipArchiveEntry> entries,
350                                         final int index,
351                                         final String expectedName) {
352         final ZipArchiveEntry ze = entries.get(index);
353         assertEquals("src/main/java/org/apache/commons/compress/archivers/zip/"
354                      + expectedName + ".java",
355                      ze.getName());
356     }
357 }