Home | History | Annotate | Download | only in zip
      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.ByteArrayOutputStream;
     25 import java.io.File;
     26 import java.io.FileInputStream;
     27 import java.io.FileOutputStream;
     28 import java.io.IOException;
     29 import java.io.InputStream;
     30 import java.io.OutputStream;
     31 import java.nio.charset.Charset;
     32 import java.util.ArrayList;
     33 import java.util.Arrays;
     34 import java.util.Collections;
     35 import java.util.Enumeration;
     36 import java.util.HashMap;
     37 import java.util.Map;
     38 import java.util.TreeMap;
     39 import java.util.concurrent.atomic.AtomicInteger;
     40 import java.util.zip.CRC32;
     41 import java.util.zip.ZipEntry;
     42 
     43 import org.apache.commons.compress.utils.IOUtils;
     44 import org.apache.commons.compress.utils.SeekableInMemoryByteChannel;
     45 import org.junit.After;
     46 import org.junit.Assert;
     47 import org.junit.Test;
     48 
     49 public class ZipFileTest {
     50     private ZipFile zf = null;
     51 
     52     @After
     53     public void tearDown() {
     54         ZipFile.closeQuietly(zf);
     55     }
     56 
     57     @Test
     58     public void testCDOrder() throws Exception {
     59         readOrderTest();
     60         final ArrayList<ZipArchiveEntry> l = Collections.list(zf.getEntries());
     61         assertEntryName(l, 0, "AbstractUnicodeExtraField");
     62         assertEntryName(l, 1, "AsiExtraField");
     63         assertEntryName(l, 2, "ExtraFieldUtils");
     64         assertEntryName(l, 3, "FallbackZipEncoding");
     65         assertEntryName(l, 4, "GeneralPurposeBit");
     66         assertEntryName(l, 5, "JarMarker");
     67         assertEntryName(l, 6, "NioZipEncoding");
     68         assertEntryName(l, 7, "Simple8BitZipEncoding");
     69         assertEntryName(l, 8, "UnicodeCommentExtraField");
     70         assertEntryName(l, 9, "UnicodePathExtraField");
     71         assertEntryName(l, 10, "UnixStat");
     72         assertEntryName(l, 11, "UnparseableExtraFieldData");
     73         assertEntryName(l, 12, "UnrecognizedExtraField");
     74         assertEntryName(l, 13, "ZipArchiveEntry");
     75         assertEntryName(l, 14, "ZipArchiveInputStream");
     76         assertEntryName(l, 15, "ZipArchiveOutputStream");
     77         assertEntryName(l, 16, "ZipEncoding");
     78         assertEntryName(l, 17, "ZipEncodingHelper");
     79         assertEntryName(l, 18, "ZipExtraField");
     80         assertEntryName(l, 19, "ZipUtil");
     81         assertEntryName(l, 20, "ZipLong");
     82         assertEntryName(l, 21, "ZipShort");
     83         assertEntryName(l, 22, "ZipFile");
     84     }
     85 
     86     @Test
     87     public void testCDOrderInMemory() throws Exception {
     88         byte[] data = null;
     89         try (FileInputStream fis = new FileInputStream(getFile("ordertest.zip"))) {
     90             data = IOUtils.toByteArray(fis);
     91         }
     92 
     93         zf = new ZipFile(new SeekableInMemoryByteChannel(data), ZipEncodingHelper.UTF8);
     94         final ArrayList<ZipArchiveEntry> l = Collections.list(zf.getEntries());
     95         assertEntryName(l, 0, "AbstractUnicodeExtraField");
     96         assertEntryName(l, 1, "AsiExtraField");
     97         assertEntryName(l, 2, "ExtraFieldUtils");
     98         assertEntryName(l, 3, "FallbackZipEncoding");
     99         assertEntryName(l, 4, "GeneralPurposeBit");
    100         assertEntryName(l, 5, "JarMarker");
    101         assertEntryName(l, 6, "NioZipEncoding");
    102         assertEntryName(l, 7, "Simple8BitZipEncoding");
    103         assertEntryName(l, 8, "UnicodeCommentExtraField");
    104         assertEntryName(l, 9, "UnicodePathExtraField");
    105         assertEntryName(l, 10, "UnixStat");
    106         assertEntryName(l, 11, "UnparseableExtraFieldData");
    107         assertEntryName(l, 12, "UnrecognizedExtraField");
    108         assertEntryName(l, 13, "ZipArchiveEntry");
    109         assertEntryName(l, 14, "ZipArchiveInputStream");
    110         assertEntryName(l, 15, "ZipArchiveOutputStream");
    111         assertEntryName(l, 16, "ZipEncoding");
    112         assertEntryName(l, 17, "ZipEncodingHelper");
    113         assertEntryName(l, 18, "ZipExtraField");
    114         assertEntryName(l, 19, "ZipUtil");
    115         assertEntryName(l, 20, "ZipLong");
    116         assertEntryName(l, 21, "ZipShort");
    117         assertEntryName(l, 22, "ZipFile");
    118     }
    119 
    120     @Test
    121     public void testPhysicalOrder() throws Exception {
    122         readOrderTest();
    123         final ArrayList<ZipArchiveEntry> l = Collections.list(zf.getEntriesInPhysicalOrder());
    124         assertEntryName(l, 0, "AbstractUnicodeExtraField");
    125         assertEntryName(l, 1, "AsiExtraField");
    126         assertEntryName(l, 2, "ExtraFieldUtils");
    127         assertEntryName(l, 3, "FallbackZipEncoding");
    128         assertEntryName(l, 4, "GeneralPurposeBit");
    129         assertEntryName(l, 5, "JarMarker");
    130         assertEntryName(l, 6, "NioZipEncoding");
    131         assertEntryName(l, 7, "Simple8BitZipEncoding");
    132         assertEntryName(l, 8, "UnicodeCommentExtraField");
    133         assertEntryName(l, 9, "UnicodePathExtraField");
    134         assertEntryName(l, 10, "UnixStat");
    135         assertEntryName(l, 11, "UnparseableExtraFieldData");
    136         assertEntryName(l, 12, "UnrecognizedExtraField");
    137         assertEntryName(l, 13, "ZipArchiveEntry");
    138         assertEntryName(l, 14, "ZipArchiveInputStream");
    139         assertEntryName(l, 15, "ZipArchiveOutputStream");
    140         assertEntryName(l, 16, "ZipEncoding");
    141         assertEntryName(l, 17, "ZipEncodingHelper");
    142         assertEntryName(l, 18, "ZipExtraField");
    143         assertEntryName(l, 19, "ZipFile");
    144         assertEntryName(l, 20, "ZipLong");
    145         assertEntryName(l, 21, "ZipShort");
    146         assertEntryName(l, 22, "ZipUtil");
    147     }
    148 
    149     @Test
    150     public void testDoubleClose() throws Exception {
    151         readOrderTest();
    152         zf.close();
    153         try {
    154             zf.close();
    155         } catch (final Exception ex) {
    156             fail("Caught exception of second close");
    157         }
    158     }
    159 
    160     @Test
    161     public void testReadingOfStoredEntry() throws Exception {
    162         final File f = File.createTempFile("commons-compress-zipfiletest", ".zip");
    163         f.deleteOnExit();
    164         OutputStream o = null;
    165         InputStream i = null;
    166         try {
    167             o = new FileOutputStream(f);
    168             final ZipArchiveOutputStream zo = new ZipArchiveOutputStream(o);
    169             ZipArchiveEntry ze = new ZipArchiveEntry("foo");
    170             ze.setMethod(ZipEntry.STORED);
    171             ze.setSize(4);
    172             ze.setCrc(0xb63cfbcdl);
    173             zo.putArchiveEntry(ze);
    174             zo.write(new byte[] { 1, 2, 3, 4 });
    175             zo.closeArchiveEntry();
    176             zo.close();
    177             o.close();
    178             o  = null;
    179 
    180             zf = new ZipFile(f);
    181             ze = zf.getEntry("foo");
    182             assertNotNull(ze);
    183             i = zf.getInputStream(ze);
    184             final byte[] b = new byte[4];
    185             assertEquals(4, i.read(b));
    186             assertEquals(-1, i.read());
    187         } finally {
    188             if (o != null) {
    189                 o.close();
    190             }
    191             if (i != null) {
    192                 i.close();
    193             }
    194             f.delete();
    195         }
    196     }
    197 
    198     /**
    199      * @see "https://issues.apache.org/jira/browse/COMPRESS-176"
    200      */
    201     @Test
    202     public void testWinzipBackSlashWorkaround() throws Exception {
    203         final File archive = getFile("test-winzip.zip");
    204         zf = new ZipFile(archive);
    205         assertNull(zf.getEntry("\u00e4\\\u00fc.txt"));
    206         assertNotNull(zf.getEntry("\u00e4/\u00fc.txt"));
    207     }
    208 
    209     /**
    210      * Test case for
    211      * <a href="https://issues.apache.org/jira/browse/COMPRESS-208"
    212      * >COMPRESS-208</a>.
    213      */
    214     @Test
    215     public void testSkipsPK00Prefix() throws Exception {
    216         final File archive = getFile("COMPRESS-208.zip");
    217         zf = new ZipFile(archive);
    218         assertNotNull(zf.getEntry("test1.xml"));
    219         assertNotNull(zf.getEntry("test2.xml"));
    220     }
    221 
    222     @Test
    223     public void testUnixSymlinkSampleFile() throws Exception {
    224         final String entryPrefix = "COMPRESS-214_unix_symlinks/";
    225         final TreeMap<String, String> expectedVals = new TreeMap<>();
    226 
    227         // I threw in some Japanese characters to keep things interesting.
    228         expectedVals.put(entryPrefix + "link1", "../COMPRESS-214_unix_symlinks/./a/b/c/../../../\uF999");
    229         expectedVals.put(entryPrefix + "link2", "../COMPRESS-214_unix_symlinks/./a/b/c/../../../g");
    230         expectedVals.put(entryPrefix + "link3", "../COMPRESS-214_unix_symlinks/././a/b/c/../../../\u76F4\u6A39");
    231         expectedVals.put(entryPrefix + "link4", "\u82B1\u5B50/\u745B\u5B50");
    232         expectedVals.put(entryPrefix + "\uF999", "./\u82B1\u5B50/\u745B\u5B50/\u5897\u8C37/\uF999");
    233         expectedVals.put(entryPrefix + "g", "./a/b/c/d/e/f/g");
    234         expectedVals.put(entryPrefix + "\u76F4\u6A39", "./g");
    235 
    236         // Notice how a directory link might contain a trailing slash, or it might not.
    237         // Also note:  symlinks are always stored as files, even if they link to directories.
    238         expectedVals.put(entryPrefix + "link5", "../COMPRESS-214_unix_symlinks/././a/b");
    239         expectedVals.put(entryPrefix + "link6", "../COMPRESS-214_unix_symlinks/././a/b/");
    240 
    241         // I looked into creating a test with hard links, but zip does not appear to
    242         // support hard links, so nevermind.
    243 
    244         final File archive = getFile("COMPRESS-214_unix_symlinks.zip");
    245 
    246         zf = new ZipFile(archive);
    247         final Enumeration<ZipArchiveEntry> en = zf.getEntries();
    248         while (en.hasMoreElements()) {
    249             final ZipArchiveEntry zae = en.nextElement();
    250             final String link = zf.getUnixSymlink(zae);
    251             if (zae.isUnixSymlink()) {
    252                 final String name = zae.getName();
    253                 final String expected = expectedVals.get(name);
    254                 assertEquals(expected, link);
    255             } else {
    256                 // Should be null if it's not a symlink!
    257                 assertNull(link);
    258             }
    259         }
    260     }
    261 
    262     /**
    263      * @see "https://issues.apache.org/jira/browse/COMPRESS-227"
    264      */
    265     @Test
    266     public void testDuplicateEntry() throws Exception {
    267         final File archive = getFile("COMPRESS-227.zip");
    268         zf = new ZipFile(archive);
    269 
    270         final ZipArchiveEntry ze = zf.getEntry("test1.txt");
    271         assertNotNull(ze);
    272         assertNotNull(zf.getInputStream(ze));
    273 
    274         int numberOfEntries = 0;
    275         for (final ZipArchiveEntry entry : zf.getEntries("test1.txt")) {
    276             numberOfEntries++;
    277             assertNotNull(zf.getInputStream(entry));
    278         }
    279         assertEquals(2, numberOfEntries);
    280     }
    281 
    282     /**
    283      * @see "https://issues.apache.org/jira/browse/COMPRESS-228"
    284      */
    285     @Test
    286     public void testExcessDataInZip64ExtraField() throws Exception {
    287         final File archive = getFile("COMPRESS-228.zip");
    288         zf = new ZipFile(archive);
    289         // actually, if we get here, the test already has passed
    290 
    291         final ZipArchiveEntry ze = zf.getEntry("src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java");
    292         assertEquals(26101, ze.getSize());
    293     }
    294 
    295     @Test
    296     public void testUnshrinking() throws Exception {
    297         zf = new ZipFile(getFile("SHRUNK.ZIP"));
    298         ZipArchiveEntry test = zf.getEntry("TEST1.XML");
    299         FileInputStream original = new FileInputStream(getFile("test1.xml"));
    300         try {
    301             assertArrayEquals(IOUtils.toByteArray(original),
    302                               IOUtils.toByteArray(zf.getInputStream(test)));
    303         } finally {
    304             original.close();
    305         }
    306         test = zf.getEntry("TEST2.XML");
    307         original = new FileInputStream(getFile("test2.xml"));
    308         try {
    309             assertArrayEquals(IOUtils.toByteArray(original),
    310                               IOUtils.toByteArray(zf.getInputStream(test)));
    311         } finally {
    312             original.close();
    313         }
    314     }
    315 
    316     /**
    317      * Test case for
    318      * <a href="https://issues.apache.org/jira/browse/COMPRESS-264"
    319      * >COMPRESS-264</a>.
    320      */
    321     @Test
    322     public void testReadingOfFirstStoredEntry() throws Exception {
    323         final File archive = getFile("COMPRESS-264.zip");
    324         zf = new ZipFile(archive);
    325         final ZipArchiveEntry ze = zf.getEntry("test.txt");
    326         assertEquals(5, ze.getSize());
    327         assertArrayEquals(new byte[] {'d', 'a', 't', 'a', '\n'},
    328                           IOUtils.toByteArray(zf.getInputStream(ze)));
    329     }
    330 
    331     @Test
    332     public void testUnzipBZip2CompressedEntry() throws Exception {
    333         final File archive = getFile("bzip2-zip.zip");
    334         zf = new ZipFile(archive);
    335         final ZipArchiveEntry ze = zf.getEntry("lots-of-as");
    336         assertEquals(42, ze.getSize());
    337         final byte[] expected = new byte[42];
    338         Arrays.fill(expected , (byte)'a');
    339         assertArrayEquals(expected, IOUtils.toByteArray(zf.getInputStream(ze)));
    340     }
    341 
    342     @Test
    343     public void testConcurrentReadSeekable() throws Exception {
    344         // mixed.zip contains both inflated and stored files
    345         byte[] data = null;
    346         try (FileInputStream fis = new FileInputStream(getFile("mixed.zip"))) {
    347             data = IOUtils.toByteArray(fis);
    348         }
    349         zf = new ZipFile(new SeekableInMemoryByteChannel(data), ZipEncodingHelper.UTF8);
    350 
    351         final Map<String, byte[]> content = new HashMap<String, byte[]>();
    352         for (ZipArchiveEntry entry: Collections.list(zf.getEntries())) {
    353             content.put(entry.getName(), IOUtils.toByteArray(zf.getInputStream(entry)));
    354         }
    355 
    356         final AtomicInteger passedCount = new AtomicInteger();
    357         Runnable run = new Runnable() {
    358             @Override
    359             public void run() {
    360                 for (ZipArchiveEntry entry: Collections.list(zf.getEntries())) {
    361                     assertAllReadMethods(content.get(entry.getName()), zf, entry);
    362                 }
    363                 passedCount.incrementAndGet();
    364             }
    365         };
    366         Thread t0 = new Thread(run);
    367         Thread t1 = new Thread(run);
    368         t0.start();
    369         t1.start();
    370         t0.join();
    371         t1.join();
    372         assertEquals(2, passedCount.get());
    373     }
    374 
    375     @Test
    376     public void testConcurrentReadFile() throws Exception {
    377         // mixed.zip contains both inflated and stored files
    378         final File archive = getFile("mixed.zip");
    379         zf = new ZipFile(archive);
    380 
    381         final Map<String, byte[]> content = new HashMap<String, byte[]>();
    382         for (ZipArchiveEntry entry: Collections.list(zf.getEntries())) {
    383             content.put(entry.getName(), IOUtils.toByteArray(zf.getInputStream(entry)));
    384         }
    385 
    386         final AtomicInteger passedCount = new AtomicInteger();
    387         Runnable run = new Runnable() {
    388             @Override
    389             public void run() {
    390                 for (ZipArchiveEntry entry: Collections.list(zf.getEntries())) {
    391                     assertAllReadMethods(content.get(entry.getName()), zf, entry);
    392                 }
    393                 passedCount.incrementAndGet();
    394             }
    395         };
    396         Thread t0 = new Thread(run);
    397         Thread t1 = new Thread(run);
    398         t0.start();
    399         t1.start();
    400         t0.join();
    401         t1.join();
    402         assertEquals(2, passedCount.get());
    403     }
    404 
    405     /**
    406      * Test correct population of header and data offsets.
    407      */
    408     @Test
    409     public void testOffsets() throws Exception {
    410         // mixed.zip contains both inflated and stored files
    411         final File archive = getFile("mixed.zip");
    412         try (ZipFile zf = new ZipFile(archive)) {
    413             ZipArchiveEntry inflatedEntry = zf.getEntry("inflated.txt");
    414             Assert.assertEquals(0x0000, inflatedEntry.getLocalHeaderOffset());
    415             Assert.assertEquals(0x0046, inflatedEntry.getDataOffset());
    416             Assert.assertTrue(inflatedEntry.isStreamContiguous());
    417             ZipArchiveEntry storedEntry = zf.getEntry("stored.txt");
    418             Assert.assertEquals(0x5892, storedEntry.getLocalHeaderOffset());
    419             Assert.assertEquals(0x58d6, storedEntry.getDataOffset());
    420             Assert.assertTrue(inflatedEntry.isStreamContiguous());
    421         }
    422     }
    423 
    424     /**
    425      * Test correct population of header and data offsets when they are written after stream.
    426      */
    427     @Test
    428     public void testDelayedOffsetsAndSizes() throws Exception {
    429         ByteArrayOutputStream zipContent = new ByteArrayOutputStream();
    430         try (ZipArchiveOutputStream zipOutput = new ZipArchiveOutputStream(zipContent)) {
    431             ZipArchiveEntry inflatedEntry = new ZipArchiveEntry("inflated.txt");
    432             inflatedEntry.setMethod(ZipEntry.DEFLATED);
    433             zipOutput.putArchiveEntry(inflatedEntry);
    434             zipOutput.write("Hello Deflated\n".getBytes());
    435             zipOutput.closeArchiveEntry();
    436 
    437             byte[] storedContent = "Hello Stored\n".getBytes();
    438             ZipArchiveEntry storedEntry = new ZipArchiveEntry("stored.txt");
    439             storedEntry.setMethod(ZipEntry.STORED);
    440             storedEntry.setSize(storedContent.length);
    441             storedEntry.setCrc(calculateCrc32(storedContent));
    442             zipOutput.putArchiveEntry(storedEntry);
    443             zipOutput.write("Hello Stored\n".getBytes());
    444             zipOutput.closeArchiveEntry();
    445 
    446         }
    447 
    448         try (ZipFile zf = new ZipFile(new SeekableInMemoryByteChannel(zipContent.toByteArray()))) {
    449             ZipArchiveEntry inflatedEntry = zf.getEntry("inflated.txt");
    450             Assert.assertNotEquals(-1L, inflatedEntry.getLocalHeaderOffset());
    451             Assert.assertNotEquals(-1L, inflatedEntry.getDataOffset());
    452             Assert.assertTrue(inflatedEntry.isStreamContiguous());
    453             Assert.assertNotEquals(-1L, inflatedEntry.getCompressedSize());
    454             Assert.assertNotEquals(-1L, inflatedEntry.getSize());
    455             ZipArchiveEntry storedEntry = zf.getEntry("stored.txt");
    456             Assert.assertNotEquals(-1L, storedEntry.getLocalHeaderOffset());
    457             Assert.assertNotEquals(-1L, storedEntry.getDataOffset());
    458             Assert.assertTrue(inflatedEntry.isStreamContiguous());
    459             Assert.assertNotEquals(-1L, storedEntry.getCompressedSize());
    460             Assert.assertNotEquals(-1L, storedEntry.getSize());
    461         }
    462     }
    463 
    464     /**
    465      * Test entries alignment.
    466      */
    467     @Test
    468     public void testEntryAlignment() throws Exception {
    469         SeekableInMemoryByteChannel zipContent = new SeekableInMemoryByteChannel();
    470         try (ZipArchiveOutputStream zipOutput = new ZipArchiveOutputStream(zipContent)) {
    471             ZipArchiveEntry inflatedEntry = new ZipArchiveEntry("inflated.txt");
    472             inflatedEntry.setMethod(ZipEntry.DEFLATED);
    473             inflatedEntry.setAlignment(1024);
    474             zipOutput.putArchiveEntry(inflatedEntry);
    475             zipOutput.write("Hello Deflated\n".getBytes(Charset.forName("UTF-8")));
    476             zipOutput.closeArchiveEntry();
    477 
    478             ZipArchiveEntry storedEntry = new ZipArchiveEntry("stored.txt");
    479             storedEntry.setMethod(ZipEntry.STORED);
    480             storedEntry.setAlignment(1024);
    481             zipOutput.putArchiveEntry(storedEntry);
    482             zipOutput.write("Hello Stored\n".getBytes(Charset.forName("UTF-8")));
    483             zipOutput.closeArchiveEntry();
    484 
    485             ZipArchiveEntry storedEntry2 = new ZipArchiveEntry("stored2.txt");
    486             storedEntry2.setMethod(ZipEntry.STORED);
    487             storedEntry2.setAlignment(1024);
    488             storedEntry2.addExtraField(new ResourceAlignmentExtraField(1));
    489             zipOutput.putArchiveEntry(storedEntry2);
    490             zipOutput.write("Hello overload-alignment Stored\n".getBytes(Charset.forName("UTF-8")));
    491             zipOutput.closeArchiveEntry();
    492 
    493             ZipArchiveEntry storedEntry3 = new ZipArchiveEntry("stored3.txt");
    494             storedEntry3.setMethod(ZipEntry.STORED);
    495             storedEntry3.addExtraField(new ResourceAlignmentExtraField(1024));
    496             zipOutput.putArchiveEntry(storedEntry3);
    497             zipOutput.write("Hello copy-alignment Stored\n".getBytes(Charset.forName("UTF-8")));
    498             zipOutput.closeArchiveEntry();
    499 
    500         }
    501 
    502         try (ZipFile zf = new ZipFile(new SeekableInMemoryByteChannel(
    503                         Arrays.copyOfRange(zipContent.array(), 0, (int)zipContent.size())
    504         ))) {
    505             ZipArchiveEntry inflatedEntry = zf.getEntry("inflated.txt");
    506             ResourceAlignmentExtraField inflatedAlignmentEx =
    507                             (ResourceAlignmentExtraField)inflatedEntry.getExtraField(ResourceAlignmentExtraField.ID);
    508             assertNotEquals(-1L, inflatedEntry.getCompressedSize());
    509             assertNotEquals(-1L, inflatedEntry.getSize());
    510             assertEquals(0L, inflatedEntry.getDataOffset()%1024);
    511             assertNotNull(inflatedAlignmentEx);
    512             assertEquals(1024, inflatedAlignmentEx.getAlignment());
    513             assertFalse(inflatedAlignmentEx.allowMethodChange());
    514             try (InputStream stream = zf.getInputStream(inflatedEntry)) {
    515                 Assert.assertEquals("Hello Deflated\n",
    516                                 new String(IOUtils.toByteArray(stream), Charset.forName("UTF-8")));
    517             }
    518             ZipArchiveEntry storedEntry = zf.getEntry("stored.txt");
    519             ResourceAlignmentExtraField storedAlignmentEx =
    520                             (ResourceAlignmentExtraField)storedEntry.getExtraField(ResourceAlignmentExtraField.ID);
    521             assertNotEquals(-1L, storedEntry.getCompressedSize());
    522             assertNotEquals(-1L, storedEntry.getSize());
    523             assertEquals(0L, storedEntry.getDataOffset()%1024);
    524             assertNotNull(storedAlignmentEx);
    525             assertEquals(1024, storedAlignmentEx.getAlignment());
    526             assertFalse(storedAlignmentEx.allowMethodChange());
    527             try (InputStream stream = zf.getInputStream(storedEntry)) {
    528                 Assert.assertEquals("Hello Stored\n",
    529                                 new String(IOUtils.toByteArray(stream), Charset.forName("UTF-8")));
    530             }
    531 
    532             ZipArchiveEntry storedEntry2 = zf.getEntry("stored2.txt");
    533             ResourceAlignmentExtraField stored2AlignmentEx =
    534                             (ResourceAlignmentExtraField)storedEntry2.getExtraField(ResourceAlignmentExtraField.ID);
    535             assertNotEquals(-1L, storedEntry2.getCompressedSize());
    536             assertNotEquals(-1L, storedEntry2.getSize());
    537             assertEquals(0L, storedEntry2.getDataOffset()%1024);
    538             assertNotNull(stored2AlignmentEx);
    539             assertEquals(1024, stored2AlignmentEx.getAlignment());
    540             assertFalse(stored2AlignmentEx.allowMethodChange());
    541             try (InputStream stream = zf.getInputStream(storedEntry2)) {
    542                 Assert.assertEquals("Hello overload-alignment Stored\n",
    543                                 new String(IOUtils.toByteArray(stream), Charset.forName("UTF-8")));
    544             }
    545 
    546             ZipArchiveEntry storedEntry3 = zf.getEntry("stored3.txt");
    547             ResourceAlignmentExtraField stored3AlignmentEx =
    548                             (ResourceAlignmentExtraField)storedEntry3.getExtraField(ResourceAlignmentExtraField.ID);
    549             assertNotEquals(-1L, storedEntry3.getCompressedSize());
    550             assertNotEquals(-1L, storedEntry3.getSize());
    551             assertEquals(0L, storedEntry3.getDataOffset()%1024);
    552             assertNotNull(stored3AlignmentEx);
    553             assertEquals(1024, stored3AlignmentEx.getAlignment());
    554             assertFalse(stored3AlignmentEx.allowMethodChange());
    555             try (InputStream stream = zf.getInputStream(storedEntry3)) {
    556                 Assert.assertEquals("Hello copy-alignment Stored\n",
    557                                 new String(IOUtils.toByteArray(stream), Charset.forName("UTF-8")));
    558             }
    559         }
    560     }
    561 
    562     /**
    563      * Test too big alignment, resulting into exceeding extra field limit.
    564      */
    565     @Test(expected = IllegalArgumentException.class)
    566     public void testEntryAlignmentExceed() throws Exception {
    567         SeekableInMemoryByteChannel zipContent = new SeekableInMemoryByteChannel();
    568         try (ZipArchiveOutputStream zipOutput = new ZipArchiveOutputStream(zipContent)) {
    569             ZipArchiveEntry inflatedEntry = new ZipArchiveEntry("inflated.txt");
    570             inflatedEntry.setMethod(ZipEntry.STORED);
    571             inflatedEntry.setAlignment(0x20000);
    572         }
    573     }
    574 
    575     /**
    576      * Test non power of 2 alignment.
    577      */
    578     @Test(expected = IllegalArgumentException.class)
    579     public void testInvalidAlignment() throws Exception {
    580         ZipArchiveEntry entry = new ZipArchiveEntry("dummy");
    581         entry.setAlignment(3);
    582     }
    583 
    584     @Test
    585     public void nameSourceDefaultsToName() throws Exception {
    586         nameSource("bla.zip", "test1.xml", ZipArchiveEntry.NameSource.NAME);
    587     }
    588 
    589     @Test
    590     public void nameSourceIsSetToUnicodeExtraField() throws Exception {
    591         nameSource("utf8-winzip-test.zip", "\u20AC_for_Dollar.txt",
    592                    ZipArchiveEntry.NameSource.UNICODE_EXTRA_FIELD);
    593     }
    594 
    595     @Test
    596     public void nameSourceIsSetToEFS() throws Exception {
    597         nameSource("utf8-7zip-test.zip", "\u20AC_for_Dollar.txt",
    598                    ZipArchiveEntry.NameSource.NAME_WITH_EFS_FLAG);
    599     }
    600 
    601     /**
    602      * @see "https://issues.apache.org/jira/browse/COMPRESS-380"
    603      */
    604     @Test
    605     public void readDeflate64CompressedStream() throws Exception {
    606         final File input = getFile("COMPRESS-380/COMPRESS-380-input");
    607         final File archive = getFile("COMPRESS-380/COMPRESS-380.zip");
    608         try (FileInputStream in = new FileInputStream(input);
    609              ZipFile zf = new ZipFile(archive)) {
    610             byte[] orig = IOUtils.toByteArray(in);
    611             ZipArchiveEntry e = zf.getEntry("input2");
    612             try (InputStream s = zf.getInputStream(e)) {
    613                 byte[] fromZip = IOUtils.toByteArray(s);
    614                 assertArrayEquals(orig, fromZip);
    615             }
    616         }
    617     }
    618 
    619     @Test
    620     public void singleByteReadConsistentlyReturnsMinusOneAtEofUsingDeflate() throws Exception {
    621         singleByteReadConsistentlyReturnsMinusOneAtEof(getFile("bla.zip"));
    622     }
    623 
    624     @Test
    625     public void singleByteReadConsistentlyReturnsMinusOneAtEofUsingStore() throws Exception {
    626         singleByteReadConsistentlyReturnsMinusOneAtEof(getFile("COMPRESS-264.zip"));
    627     }
    628 
    629     @Test
    630     public void singleByteReadConsistentlyReturnsMinusOneAtEofUsingUnshrink() throws Exception {
    631         singleByteReadConsistentlyReturnsMinusOneAtEof(getFile("SHRUNK.ZIP"));
    632     }
    633 
    634     @Test
    635     public void singleByteReadConsistentlyReturnsMinusOneAtEofUsingExplode() throws Exception {
    636         singleByteReadConsistentlyReturnsMinusOneAtEof(getFile("imploding-8Kdict-3trees.zip"));
    637     }
    638 
    639     @Test
    640     public void singleByteReadConsistentlyReturnsMinusOneAtEofUsingDeflate64() throws Exception {
    641         singleByteReadConsistentlyReturnsMinusOneAtEof(getFile("COMPRESS-380/COMPRESS-380.zip"));
    642     }
    643 
    644     @Test
    645     public void singleByteReadConsistentlyReturnsMinusOneAtEofUsingBzip2() throws Exception {
    646         singleByteReadConsistentlyReturnsMinusOneAtEof(getFile("bzip2-zip.zip"));
    647     }
    648 
    649     private void singleByteReadConsistentlyReturnsMinusOneAtEof(File file) throws Exception {
    650         try (ZipFile archive = new ZipFile(file)) {
    651             ZipArchiveEntry e = archive.getEntries().nextElement();
    652             try (InputStream is = archive.getInputStream(e)) {
    653                 IOUtils.toByteArray(is);
    654                 assertEquals(-1, is.read());
    655                 assertEquals(-1, is.read());
    656             }
    657         }
    658     }
    659 
    660     @Test
    661     public void multiByteReadConsistentlyReturnsMinusOneAtEofUsingDeflate() throws Exception {
    662         multiByteReadConsistentlyReturnsMinusOneAtEof(getFile("bla.zip"));
    663     }
    664 
    665     @Test
    666     public void multiByteReadConsistentlyReturnsMinusOneAtEofUsingStore() throws Exception {
    667         multiByteReadConsistentlyReturnsMinusOneAtEof(getFile("COMPRESS-264.zip"));
    668     }
    669 
    670     @Test
    671     public void multiByteReadConsistentlyReturnsMinusOneAtEofUsingUnshrink() throws Exception {
    672         multiByteReadConsistentlyReturnsMinusOneAtEof(getFile("SHRUNK.ZIP"));
    673     }
    674 
    675     @Test
    676     public void multiByteReadConsistentlyReturnsMinusOneAtEofUsingExplode() throws Exception {
    677         multiByteReadConsistentlyReturnsMinusOneAtEof(getFile("imploding-8Kdict-3trees.zip"));
    678     }
    679 
    680     @Test
    681     public void multiByteReadConsistentlyReturnsMinusOneAtEofUsingDeflate64() throws Exception {
    682         multiByteReadConsistentlyReturnsMinusOneAtEof(getFile("COMPRESS-380/COMPRESS-380.zip"));
    683     }
    684 
    685     @Test
    686     public void multiByteReadConsistentlyReturnsMinusOneAtEofUsingBzip2() throws Exception {
    687         multiByteReadConsistentlyReturnsMinusOneAtEof(getFile("bzip2-zip.zip"));
    688     }
    689 
    690     private void multiByteReadConsistentlyReturnsMinusOneAtEof(File file) throws Exception {
    691         byte[] buf = new byte[2];
    692         try (ZipFile archive = new ZipFile(file)) {
    693             ZipArchiveEntry e = archive.getEntries().nextElement();
    694             try (InputStream is = archive.getInputStream(e)) {
    695                 IOUtils.toByteArray(is);
    696                 assertEquals(-1, is.read(buf));
    697                 assertEquals(-1, is.read(buf));
    698             }
    699         }
    700     }
    701 
    702     private void assertAllReadMethods(byte[] expected, ZipFile zipFile, ZipArchiveEntry entry) {
    703         // simple IOUtil read
    704         try (InputStream stream = zf.getInputStream(entry)) {
    705             byte[] full = IOUtils.toByteArray(stream);
    706             assertArrayEquals(expected, full);
    707         }
    708         catch (IOException ex) {
    709             throw new RuntimeException(ex);
    710         }
    711 
    712         // big buffer at the beginning and then chunks by IOUtils read
    713         try (InputStream stream = zf.getInputStream(entry)) {
    714             byte[] full;
    715             byte[] bytes = new byte[0x40000];
    716             int read = stream.read(bytes);
    717             if (read < 0) {
    718                 full = new byte[0];
    719             }
    720             else {
    721                 full = readStreamRest(bytes, read, stream);
    722             }
    723             assertArrayEquals(expected, full);
    724         }
    725         catch (IOException ex) {
    726             throw new RuntimeException(ex);
    727         }
    728 
    729         // small chunk / single byte and big buffer then
    730         try (InputStream stream = zf.getInputStream(entry)) {
    731             byte[] full;
    732             int single = stream.read();
    733             if (single < 0) {
    734                 full = new byte[0];
    735             }
    736             else {
    737                 byte[] big = new byte[0x40000];
    738                 big[0] = (byte)single;
    739                 int read = stream.read(big, 1, big.length-1);
    740                 if (read < 0) {
    741                     full = new byte[]{ (byte)single };
    742                 }
    743                 else {
    744                     full = readStreamRest(big, read+1, stream);
    745                 }
    746             }
    747             assertArrayEquals(expected, full);
    748         }
    749         catch (IOException ex) {
    750             throw new RuntimeException(ex);
    751         }
    752     }
    753 
    754     /**
    755      * Utility to append the rest of the stream to already read data.
    756      */
    757     private byte[] readStreamRest(byte[] beginning, int length, InputStream stream) throws IOException {
    758         byte[] rest = IOUtils.toByteArray(stream);
    759         byte[] full = new byte[length+rest.length];
    760         System.arraycopy(beginning, 0, full, 0, length);
    761         System.arraycopy(rest, 0, full, length, rest.length);
    762         return full;
    763     }
    764 
    765     private long calculateCrc32(byte[] content) {
    766         CRC32 crc = new CRC32();
    767         crc.update(content);
    768         return crc.getValue();
    769     }
    770 
    771     /*
    772      * ordertest.zip has been handcrafted.
    773      *
    774      * It contains enough files so any random coincidence of
    775      * entries.keySet() and central directory order would be unlikely
    776      * - in fact testCDOrder fails in svn revision 920284.
    777      *
    778      * The central directory has ZipFile and ZipUtil swapped so
    779      * central directory order is different from entry data order.
    780      */
    781     private void readOrderTest() throws Exception {
    782         final File archive = getFile("ordertest.zip");
    783         zf = new ZipFile(archive);
    784     }
    785 
    786     private static void assertEntryName(final ArrayList<ZipArchiveEntry> entries,
    787                                         final int index,
    788                                         final String expectedName) {
    789         final ZipArchiveEntry ze = entries.get(index);
    790         assertEquals("src/main/java/org/apache/commons/compress/archivers/zip/"
    791                      + expectedName + ".java",
    792                      ze.getName());
    793     }
    794 
    795     private static void nameSource(String archive, String entry, ZipArchiveEntry.NameSource expected) throws Exception {
    796         try (ZipFile zf = new ZipFile(getFile(archive))) {
    797             ZipArchiveEntry ze = zf.getEntry(entry);
    798             assertEquals(entry, ze.getName());
    799             assertEquals(expected, ze.getNameSource());
    800         }
    801     }
    802 }
    803