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.assertArrayEquals;
23  import static org.junit.Assert.assertEquals;
24  import static org.junit.Assert.assertTrue;
25  import static org.junit.Assert.fail;
26  
27  import java.io.BufferedInputStream;
28  import java.io.EOFException;
29  import java.io.FileInputStream;
30  import java.io.IOException;
31  import java.io.InputStream;
32  import java.util.Arrays;
33  import java.util.zip.ZipException;
34  
35  import org.apache.commons.compress.utils.IOUtils;
36  import org.junit.Test;
37  
38  public class ZipArchiveInputStreamTest {
39  
40      /**
41       * @see "https://issues.apache.org/jira/browse/COMPRESS-176"
42       */
43      @Test
44      public void winzipBackSlashWorkaround() throws Exception {
45          ZipArchiveInputStream in = null;
46          try {
47              in = new ZipArchiveInputStream(new FileInputStream(getFile("test-winzip.zip")));
48              ZipArchiveEntry zae = in.getNextZipEntry();
49              zae = in.getNextZipEntry();
50              zae = in.getNextZipEntry();
51              assertEquals("\u00e4/", zae.getName());
52          } finally {
53              if (in != null) {
54                  in.close();
55              }
56          }
57      }
58  
59      /**
60       * @see "https://issues.apache.org/jira/browse/COMPRESS-189"
61       */
62      @Test
63      public void properUseOfInflater() throws Exception {
64          ZipFile zf = null;
65          ZipArchiveInputStream in = null;
66          try {
67              zf = new ZipFile(getFile("COMPRESS-189.zip"));
68              final ZipArchiveEntry zae = zf.getEntry("USD0558682-20080101.ZIP");
69              in = new ZipArchiveInputStream(new BufferedInputStream(zf.getInputStream(zae)));
70              ZipArchiveEntry innerEntry;
71              while ((innerEntry = in.getNextZipEntry()) != null) {
72                  if (innerEntry.getName().endsWith("XML")) {
73                      assertTrue(0 < in.read());
74                  }
75              }
76          } finally {
77              if (zf != null) {
78                  zf.close();
79              }
80              if (in != null) {
81                  in.close();
82              }
83          }
84      }
85  
86      @Test
87      public void shouldConsumeArchiveCompletely() throws Exception {
88          final InputStream is = ZipArchiveInputStreamTest.class
89              .getResourceAsStream("/archive_with_trailer.zip");
90          final ZipArchiveInputStream zip = new ZipArchiveInputStream(is);
91          while (zip.getNextZipEntry() != null) {
92              // just consume the archive
93          }
94          final byte[] expected = new byte[] {
95              'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!', '\n'
96          };
97          final byte[] actual = new byte[expected.length];
98          is.read(actual);
99          assertArrayEquals(expected, actual);
100         zip.close();
101     }
102 
103     /**
104      * @see "https://issues.apache.org/jira/browse/COMPRESS-219"
105      */
106     @Test
107     public void shouldReadNestedZip() throws IOException {
108         ZipArchiveInputStream in = null;
109         try {
110             in = new ZipArchiveInputStream(new FileInputStream(getFile("COMPRESS-219.zip")));
111             extractZipInputStream(in);
112         } finally {
113             if (in != null) {
114                 in.close();
115             }
116         }
117     }
118 
119     private void extractZipInputStream(final ZipArchiveInputStream in)
120         throws IOException {
121         ZipArchiveEntry zae = in.getNextZipEntry();
122         while (zae != null) {
123             if (zae.getName().endsWith(".zip")) {
124                 extractZipInputStream(new ZipArchiveInputStream(in));
125             }
126             zae = in.getNextZipEntry();
127         }
128     }
129 
130     @Test
131     public void testUnshrinkEntry() throws Exception {
132         final ZipArchiveInputStream in = new ZipArchiveInputStream(new FileInputStream(getFile("SHRUNK.ZIP")));
133         
134         ZipArchiveEntry entry = in.getNextZipEntry();
135         assertEquals("method", ZipMethod.UNSHRINKING.getCode(), entry.getMethod());
136         assertTrue(in.canReadEntryData(entry));
137         
138         FileInputStream original = new FileInputStream(getFile("test1.xml"));
139         try {
140             assertArrayEquals(IOUtils.toByteArray(original), IOUtils.toByteArray(in));
141         } finally {
142             original.close();
143         }
144         
145         entry = in.getNextZipEntry();
146         assertEquals("method", ZipMethod.UNSHRINKING.getCode(), entry.getMethod());
147         assertTrue(in.canReadEntryData(entry));
148         
149         original = new FileInputStream(getFile("test2.xml"));
150         try {
151             assertArrayEquals(IOUtils.toByteArray(original), IOUtils.toByteArray(in));
152         } finally {
153             original.close();
154         }
155     }
156 
157 
158     /**
159      * Test case for 
160      * <a href="https://issues.apache.org/jira/browse/COMPRESS-264"
161      * >COMPRESS-264</a>.
162      */
163     @Test
164     public void testReadingOfFirstStoredEntry() throws Exception {
165 
166         try (ZipArchiveInputStream in = new ZipArchiveInputStream(new FileInputStream(getFile("COMPRESS-264.zip")))) {
167             final ZipArchiveEntry ze = in.getNextZipEntry();
168             assertEquals(5, ze.getSize());
169             assertArrayEquals(new byte[] { 'd', 'a', 't', 'a', '\n' },
170                     IOUtils.toByteArray(in));
171         }
172     }
173 
174     /**
175      * Test case for
176      * <a href="https://issues.apache.org/jira/browse/COMPRESS-351"
177      * >COMPRESS-351</a>.
178      */
179     @Test
180     public void testMessageWithCorruptFileName() throws Exception {
181         try (ZipArchiveInputStream in = new ZipArchiveInputStream(new FileInputStream(getFile("COMPRESS-351.zip")))) {
182             ZipArchiveEntry ze = in.getNextZipEntry();
183             while (ze != null) {
184                 ze = in.getNextZipEntry();
185             }
186             fail("expected EOFException");
187         } catch (final EOFException ex) {
188             final String m = ex.getMessage();
189             assertTrue(m.startsWith("Truncated ZIP entry: ?2016")); // the first character is not printable
190         }
191     }
192 
193     @Test
194     public void testUnzipBZip2CompressedEntry() throws Exception {
195 
196         try (ZipArchiveInputStream in = new ZipArchiveInputStream(new FileInputStream(getFile("bzip2-zip.zip")))) {
197             final ZipArchiveEntry ze = in.getNextZipEntry();
198             assertEquals(42, ze.getSize());
199             final byte[] expected = new byte[42];
200             Arrays.fill(expected, (byte) 'a');
201             assertArrayEquals(expected, IOUtils.toByteArray(in));
202         }
203     }
204 
205     /**
206      * Test case for
207      * <a href="https://issues.apache.org/jira/browse/COMPRESS-364"
208      * >COMPRESS-364</a>.
209      */
210     @Test
211     public void testWithBytesAfterData() throws Exception {
212         final int expectedNumEntries = 2;
213         final InputStream is = ZipArchiveInputStreamTest.class
214                 .getResourceAsStream("/archive_with_bytes_after_data.zip");
215         final ZipArchiveInputStream zip = new ZipArchiveInputStream(is);
216 
217         try {
218             int actualNumEntries = 0;
219             ZipArchiveEntry zae = zip.getNextZipEntry();
220             while (zae != null) {
221                 actualNumEntries++;
222                 readEntry(zip, zae);
223                 zae = zip.getNextZipEntry();
224             }
225             assertEquals(expectedNumEntries, actualNumEntries);
226         } finally {
227             zip.close();
228         }
229     }
230 
231     /**
232      * <code>getNextZipEntry()</code> should throw a <code>ZipException</code> rather than return
233      * <code>null</code> when an unexpected structure is encountered.
234      */
235     @Test
236     public void testThrowOnInvalidEntry() throws Exception {
237         final InputStream is = ZipArchiveInputStreamTest.class
238                 .getResourceAsStream("/invalid-zip.zip");
239         final ZipArchiveInputStream zip = new ZipArchiveInputStream(is);
240 
241         try {
242             zip.getNextZipEntry();
243             fail("IOException expected");
244         } catch (ZipException expected) {
245             assertTrue(expected.getMessage().contains("Unexpected record signature"));
246         } finally {
247             zip.close();
248         }
249     }
250 
251     private static byte[] readEntry(ZipArchiveInputStream zip, ZipArchiveEntry zae) throws IOException {
252         final int len = (int)zae.getSize();
253         final byte[] buff = new byte[len];
254         zip.read(buff, 0, len);
255 
256         return buff;
257     }
258 }