1 /* 2 * Copyright (C) 2016 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 com.android.tools.build.apkzlib.zip; 18 19 import static org.junit.Assert.assertArrayEquals; 20 import static org.junit.Assert.assertEquals; 21 import static org.junit.Assert.assertFalse; 22 import static org.junit.Assert.assertNotNull; 23 import static org.junit.Assert.assertSame; 24 import static org.junit.Assert.assertTrue; 25 26 import com.android.tools.build.apkzlib.utils.CachedFileContents; 27 import com.google.common.base.Charsets; 28 import com.google.common.hash.Hashing; 29 import com.google.common.io.ByteStreams; 30 import com.google.common.io.Closer; 31 import java.io.ByteArrayOutputStream; 32 import java.io.File; 33 import java.io.FileOutputStream; 34 import java.util.zip.ZipEntry; 35 import java.util.zip.ZipOutputStream; 36 import org.junit.Rule; 37 import org.junit.Test; 38 import org.junit.rules.TemporaryFolder; 39 40 public class ZipMergeTest { 41 @Rule 42 public TemporaryFolder mTemporaryFolder = new TemporaryFolder(); 43 44 @Test 45 public void mergeZip() throws Exception { 46 File aZip = ZipTestUtils.cloneRsrc("simple-zip.zip", mTemporaryFolder, "a.zip"); 47 48 CachedFileContents<Object> changeDetector; 49 File merged = new File(mTemporaryFolder.getRoot(), "r.zip"); 50 try (ZFile mergedZf = new ZFile(merged)) { 51 mergedZf.mergeFrom(new ZFile(aZip), f -> false); 52 mergedZf.close(); 53 54 assertEquals(3, mergedZf.entries().size()); 55 56 StoredEntry e0 = mergedZf.get("dir/"); 57 assertNotNull(e0); 58 assertSame(StoredEntryType.DIRECTORY, e0.getType()); 59 60 StoredEntry e1 = mergedZf.get("dir/inside"); 61 assertNotNull(e1); 62 assertSame(StoredEntryType.FILE, e1.getType()); 63 ByteArrayOutputStream e1BytesOut = new ByteArrayOutputStream(); 64 ByteStreams.copy(e1.open(), e1BytesOut); 65 byte e1Bytes[] = e1BytesOut.toByteArray(); 66 String e1Txt = new String(e1Bytes, Charsets.US_ASCII); 67 assertEquals("inside", e1Txt); 68 69 StoredEntry e2 = mergedZf.get("file.txt"); 70 assertNotNull(e2); 71 assertSame(StoredEntryType.FILE, e2.getType()); 72 ByteArrayOutputStream e2BytesOut = new ByteArrayOutputStream(); 73 ByteStreams.copy(e2.open(), e2BytesOut); 74 byte e2Bytes[] = e2BytesOut.toByteArray(); 75 String e2Txt = new String(e2Bytes, Charsets.US_ASCII); 76 assertEquals("file with more text to allow deflating to be useful", e2Txt); 77 78 changeDetector = new CachedFileContents<>(merged); 79 changeDetector.closed(null); 80 81 /* 82 * Clone aZip into bZip and merge. Should have no effect on the final zip file. 83 */ 84 File bZip = ZipTestUtils.cloneRsrc("simple-zip.zip", mTemporaryFolder, "b.zip"); 85 86 mergedZf.mergeFrom(new ZFile(bZip), f -> false); 87 } 88 89 assertTrue(changeDetector.isValid()); 90 } 91 92 @Test 93 public void mergeZipWithDeferredCrc() throws Exception { 94 File foo = mTemporaryFolder.newFile("foo"); 95 96 byte[] wBytes = ZipTestUtils.rsrcBytes("text-files/wikipedia.html"); 97 98 try (ZipOutputStream fooOut = new ZipOutputStream(new FileOutputStream(foo))) { 99 fooOut.putNextEntry(new ZipEntry("w")); 100 fooOut.write(wBytes); 101 } 102 103 try (Closer closer = Closer.create()) { 104 ZFile fooZf = closer.register(new ZFile(foo)); 105 StoredEntry wStored = fooZf.get("w"); 106 assertNotNull(wStored); 107 assertTrue(wStored.getCentralDirectoryHeader().getGpBit().isDeferredCrc()); 108 assertEquals(CompressionMethod.DEFLATE, 109 wStored.getCentralDirectoryHeader().getCompressionInfoWithWait().getMethod()); 110 111 ZFile merged = closer.register(new ZFile(new File(mTemporaryFolder.getRoot(), "bar"))); 112 merged.mergeFrom(fooZf, f -> false); 113 merged.update(); 114 115 StoredEntry wmStored = merged.get("w"); 116 assertNotNull(wmStored); 117 assertFalse(wmStored.getCentralDirectoryHeader().getGpBit().isDeferredCrc()); 118 assertEquals(CompressionMethod.DEFLATE, 119 wmStored.getCentralDirectoryHeader().getCompressionInfoWithWait().getMethod()); 120 } 121 } 122 123 @Test 124 public void mergeZipKeepsDeflatedAndStored() throws Exception { 125 File foo = mTemporaryFolder.newFile("foo"); 126 127 byte[] wBytes = ZipTestUtils.rsrcBytes("text-files/wikipedia.html"); 128 byte[] lBytes = ZipTestUtils.rsrcBytes("images/lena.png"); 129 130 try (ZipOutputStream fooOut = new ZipOutputStream(new FileOutputStream(foo))) { 131 fooOut.putNextEntry(new ZipEntry("w")); 132 fooOut.write(wBytes); 133 ZipEntry le = new ZipEntry("l"); 134 le.setMethod(ZipEntry.STORED); 135 le.setSize(lBytes.length); 136 le.setCrc(Hashing.crc32().hashBytes(lBytes).padToLong()); 137 fooOut.putNextEntry(le); 138 fooOut.write(lBytes); 139 } 140 141 try (Closer closer = Closer.create()) { 142 ZFile fooZf = closer.register(new ZFile(foo)); 143 StoredEntry wStored = fooZf.get("w"); 144 assertNotNull(wStored); 145 assertEquals(CompressionMethod.DEFLATE, 146 wStored.getCentralDirectoryHeader().getCompressionInfoWithWait().getMethod()); 147 StoredEntry lStored = fooZf.get("l"); 148 assertNotNull(lStored); 149 assertEquals(CompressionMethod.STORE, 150 lStored.getCentralDirectoryHeader().getCompressionInfoWithWait().getMethod()); 151 152 ZFile merged = closer.register(new ZFile(new File(mTemporaryFolder.getRoot(), "bar"))); 153 merged.mergeFrom(fooZf, f -> false); 154 merged.update(); 155 156 StoredEntry wmStored = merged.get("w"); 157 assertNotNull(wmStored); 158 assertFalse(wmStored.getCentralDirectoryHeader().getGpBit().isDeferredCrc()); 159 assertEquals(CompressionMethod.DEFLATE, 160 wmStored.getCentralDirectoryHeader().getCompressionInfoWithWait().getMethod()); 161 assertArrayEquals(wBytes, wmStored.read()); 162 163 StoredEntry lmStored = merged.get("l"); 164 assertNotNull(lmStored); 165 assertEquals(CompressionMethod.STORE, 166 lmStored.getCentralDirectoryHeader().getCompressionInfoWithWait().getMethod()); 167 assertArrayEquals(lBytes, lmStored.read()); 168 } 169 } 170 171 @Test 172 public void mergeZipWithSorting() throws Exception { 173 File foo = mTemporaryFolder.newFile("foo"); 174 175 byte[] wBytes = ZipTestUtils.rsrcBytes("text-files/wikipedia.html"); 176 byte[] lBytes = ZipTestUtils.rsrcBytes("images/lena.png"); 177 178 try (ZipOutputStream fooOut = new ZipOutputStream(new FileOutputStream(foo))) { 179 fooOut.putNextEntry(new ZipEntry("w")); 180 fooOut.write(wBytes); 181 ZipEntry le = new ZipEntry("l"); 182 le.setMethod(ZipEntry.STORED); 183 le.setSize(lBytes.length); 184 le.setCrc(Hashing.crc32().hashBytes(lBytes).padToLong()); 185 fooOut.putNextEntry(le); 186 fooOut.write(lBytes); 187 } 188 189 try ( 190 ZFile fooZf = new ZFile(foo); 191 ZFile merged = new ZFile(new File(mTemporaryFolder.getRoot(), "bar"))) { 192 merged.mergeFrom(fooZf, f -> false); 193 merged.sortZipContents(); 194 merged.update(); 195 196 StoredEntry wmStored = merged.get("w"); 197 assertNotNull(wmStored); 198 assertArrayEquals(wBytes, wmStored.read()); 199 200 StoredEntry lmStored = merged.get("l"); 201 assertNotNull(lmStored); 202 assertArrayEquals(lBytes, lmStored.read()); 203 } 204 } 205 } 206