Home | History | Annotate | Download | only in zip
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package libcore.java.util.zip;
     18 
     19 import libcore.io.Streams;
     20 import tests.support.resource.Support_Resources;
     21 
     22 import java.io.ByteArrayInputStream;
     23 import java.io.ByteArrayOutputStream;
     24 import java.io.IOException;
     25 import java.io.InputStream;
     26 import java.util.Arrays;
     27 import java.util.Random;
     28 import java.util.zip.ZipEntry;
     29 import java.util.zip.ZipInputStream;
     30 import java.util.zip.ZipOutputStream;
     31 import libcore.junit.junit3.TestCaseWithRules;
     32 import libcore.junit.util.ResourceLeakageDetector;
     33 import org.junit.Rule;
     34 import org.junit.rules.TestRule;
     35 
     36 public final class ZipInputStreamTest extends TestCaseWithRules {
     37     @Rule
     38     public TestRule guardRule = ResourceLeakageDetector.getRule();
     39 
     40     public void testShortMessage() throws IOException {
     41         byte[] data = "Hello World".getBytes("UTF-8");
     42         byte[] zipped = ZipOutputStreamTest.zip("short", data);
     43         assertEquals(Arrays.toString(data), Arrays.toString(unzip("short", zipped)));
     44     }
     45 
     46     public void testLongMessage() throws IOException {
     47         byte[] data = new byte[1024 * 1024];
     48         new Random().nextBytes(data);
     49         assertTrue(Arrays.equals(data, unzip("r", ZipOutputStreamTest.zip("r", data))));
     50     }
     51 
     52     public static byte[] unzip(String name, byte[] bytes) throws IOException {
     53         ZipInputStream in = new ZipInputStream(new ByteArrayInputStream(bytes));
     54         ByteArrayOutputStream out = new ByteArrayOutputStream();
     55 
     56         ZipEntry entry = in.getNextEntry();
     57         assertEquals(name, entry.getName());
     58 
     59         byte[] buffer = new byte[1024];
     60         int count;
     61         while ((count = in.read(buffer)) != -1) {
     62             out.write(buffer, 0, count);
     63         }
     64 
     65         assertNull(in.getNextEntry()); // There's only one entry in the Zip files we create.
     66 
     67         in.close();
     68         return out.toByteArray();
     69     }
     70 
     71     /**
     72      * Reference implementation allows reading of empty zip using a {@link ZipInputStream}.
     73      */
     74     public void testReadEmpty() throws IOException {
     75         InputStream emptyZipIn = Support_Resources.getStream("java/util/zip/EmptyArchive.zip");
     76         ZipInputStream in = new ZipInputStream(emptyZipIn);
     77         try {
     78             ZipEntry entry = in.getNextEntry();
     79             assertNull("An empty zip has no entries", entry);
     80         } finally {
     81             in.close();
     82         }
     83     }
     84 
     85     // NOTE: Using octal because it's easiest to use "hexdump -b" to dump file contents.
     86     private static final byte[] INCOMPLETE_ZIP = new byte[] {
     87             0120, 0113, 0003, 0004, 0024, 0000, 0010, 0010, 0010, 0000, 0002, 0035, (byte) 0330,
     88             0106, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0000, 0013,
     89             0000, 0000, 0000, 0146, 0157, 0157, 0057, 0142, 0141, 0162, 0056, 0160, 0156, 0147 };
     90 
     91     // http://b//21846904
     92     public void testReadOnIncompleteStream() throws Exception {
     93         ZipInputStream zi = new ZipInputStream(new ByteArrayInputStream(INCOMPLETE_ZIP));
     94         ZipEntry ze = zi.getNextEntry();
     95 
     96         // read() and closeEntry() must throw IOExceptions to indicate that
     97         // the stream is corrupt. The bug above reported that they would loop
     98         // forever.
     99         try {
    100             zi.read(new byte[1024], 0, 1024);
    101             fail();
    102         } catch (IOException expected) {
    103         }
    104 
    105         try {
    106             zi.closeEntry();
    107             fail();
    108         } catch (IOException expected) {
    109         }
    110 
    111         zi.close();
    112     }
    113 
    114     public void testAvailable() throws Exception {
    115         // NOTE: We don't care about the contents of any of these entries as long as they're
    116         // not empty.
    117         ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(
    118                 zip(new String[] { "foo", "bar", "baz" }, new byte[] { 0, 0, 0, 1, 1, 1 })));
    119 
    120         assertEquals(1, zis.available());
    121         zis.getNextEntry();
    122         assertEquals(1, zis.available());
    123         zis.closeEntry();
    124         // On Android M and below, this call would return "1". That seems a bit odd given that the
    125         // contract for available states that we should return 1 if there are any bytes left to read
    126         // from the "current" entry.
    127         assertEquals(0, zis.available());
    128 
    129         // There shouldn't be any bytes left to read if the entry is fully consumed...
    130         zis.getNextEntry();
    131         Streams.readFullyNoClose(zis);
    132         assertEquals(0, zis.available());
    133 
    134         // ... or if the entry is fully skipped over.
    135         zis.getNextEntry();
    136         zis.skip(Long.MAX_VALUE);
    137         assertEquals(0, zis.available());
    138 
    139         // There are no entries left in the file, so there whould be nothing left to read.
    140         assertNull(zis.getNextEntry());
    141         assertEquals(0, zis.available());
    142 
    143         zis.close();
    144     }
    145 
    146     private static byte[] zip(String[] names, byte[] bytes) throws IOException {
    147         ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
    148         ZipOutputStream zippedOut = new ZipOutputStream(bytesOut);
    149 
    150         for (String name : names) {
    151             ZipEntry entry = new ZipEntry(name);
    152             zippedOut.putNextEntry(entry);
    153             zippedOut.write(bytes);
    154             zippedOut.closeEntry();
    155         }
    156 
    157         zippedOut.close();
    158         return bytesOut.toByteArray();
    159     }
    160 }
    161