131ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver/* 231ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver * Copyright 2016, Google Inc. 331ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver * All rights reserved. 431ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver * 531ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver * Redistribution and use in source and binary forms, with or without 631ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver * modification, are permitted provided that the following conditions are 731ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver * met: 831ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver * 931ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver * Redistributions of source code must retain the above copyright 1031ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver * notice, this list of conditions and the following disclaimer. 1131ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver * Redistributions in binary form must reproduce the above 1231ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver * copyright notice, this list of conditions and the following disclaimer 1331ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver * in the documentation and/or other materials provided with the 1431ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver * distribution. 1531ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver * Neither the name of Google Inc. nor the names of its 1631ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver * contributors may be used to endorse or promote products derived from 1731ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver * this software without specific prior written permission. 1831ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver * 1931ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2031ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2131ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2231ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2331ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2431ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2531ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2631ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2731ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2831ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2931ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3031ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver */ 3131ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver 3231ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruverpackage org.jf.dexlib2.dexbacked; 3331ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver 3431ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruverimport com.google.common.collect.Lists; 3531ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruverimport com.google.common.io.ByteStreams; 3631ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruverimport org.jf.dexlib2.Opcodes; 3731ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruverimport org.jf.dexlib2.dexbacked.DexBackedDexFile.NotADexFile; 3831ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruverimport org.jf.dexlib2.dexbacked.ZipDexContainer.ZipDexFile; 3931ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruverimport org.jf.dexlib2.iface.MultiDexContainer; 404eefe294e4c664577982283cc64c415819a30c1eBen Gruverimport org.jf.dexlib2.util.DexUtil; 414eefe294e4c664577982283cc64c415819a30c1eBen Gruverimport org.jf.dexlib2.util.DexUtil.InvalidFile; 424eefe294e4c664577982283cc64c415819a30c1eBen Gruverimport org.jf.dexlib2.util.DexUtil.UnsupportedFile; 4331ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver 4431ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruverimport javax.annotation.Nonnull; 4531ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruverimport javax.annotation.Nullable; 4616d4b5656b0b803689191a299d25237acf735b5bBen Gruverimport java.io.BufferedInputStream; 47dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruverimport java.io.File; 4831ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruverimport java.io.IOException; 4931ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruverimport java.io.InputStream; 5031ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruverimport java.util.Enumeration; 5131ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruverimport java.util.List; 5231ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruverimport java.util.zip.ZipEntry; 5331ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruverimport java.util.zip.ZipFile; 5431ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver 5531ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver/** 5631ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver * Represents a zip file that contains dex files (i.e. an apk or jar file) 5731ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver */ 58dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruverpublic class ZipDexContainer implements MultiDexContainer<ZipDexFile> { 5931ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver 60dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver private final File zipFilePath; 6131ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver private final Opcodes opcodes; 6231ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver 6331ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver /** 6431ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver * Constructs a new ZipDexContainer for the given zip file 6531ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver * 66dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver * @param zipFilePath The path to the zip file 6731ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver * @param opcodes The Opcodes instance to use when loading dex files from this container 6831ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver */ 69dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver public ZipDexContainer(@Nonnull File zipFilePath, @Nonnull Opcodes opcodes) { 70dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver this.zipFilePath = zipFilePath; 7131ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver this.opcodes = opcodes; 7231ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver } 7331ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver 742996766649f09b9ce9d1a6e155897dc403b1b89dBen Gruver @Nonnull @Override public Opcodes getOpcodes() { 752996766649f09b9ce9d1a6e155897dc403b1b89dBen Gruver return opcodes; 762996766649f09b9ce9d1a6e155897dc403b1b89dBen Gruver } 772996766649f09b9ce9d1a6e155897dc403b1b89dBen Gruver 7831ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver /** 7931ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver * Gets a list of the names of dex files in this zip file. 8031ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver * 8131ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver * @return A list of the names of dex files in this zip file 8231ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver */ 8331ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver @Nonnull @Override public List<String> getDexEntryNames() throws IOException { 8431ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver List<String> entryNames = Lists.newArrayList(); 85dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver ZipFile zipFile = getZipFile(); 86dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver try { 87dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver Enumeration<? extends ZipEntry> entriesEnumeration = zipFile.entries(); 88dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver 89dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver while (entriesEnumeration.hasMoreElements()) { 90dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver ZipEntry entry = entriesEnumeration.nextElement(); 9131ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver 92dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver if (!isDex(zipFile, entry)) { 93dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver continue; 94dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver } 9531ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver 96dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver entryNames.add(entry.getName()); 9731ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver } 9831ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver 99dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver return entryNames; 100dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver } finally { 101dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver zipFile.close(); 10231ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver } 10331ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver } 10431ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver 10531ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver /** 10631ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver * Loads a dex file from a specific named entry. 10731ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver * 10831ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver * @param entryName The name of the entry 10931ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver * @return A ZipDexFile, or null if there is no entry with the given name 11031ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver * @throws NotADexFile If the entry isn't a dex file 11131ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver */ 11231ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver @Nullable @Override public ZipDexFile getEntry(@Nonnull String entryName) throws IOException { 113dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver ZipFile zipFile = getZipFile(); 114dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver try { 115dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver ZipEntry entry = zipFile.getEntry(entryName); 116dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver if (entry == null) { 117dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver return null; 118dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver } 11931ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver 120dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver return loadEntry(zipFile, entry); 121dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver } finally { 122dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver zipFile.close(); 123dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver } 12431ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver } 12531ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver 126dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver public boolean isZipFile() { 127e75f2b230a1188ebfeffcb7737dfe94bcc0f9e44Albert Gorski ZipFile zipFile = null; 128dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver try { 129e75f2b230a1188ebfeffcb7737dfe94bcc0f9e44Albert Gorski zipFile = getZipFile(); 130dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver return true; 131dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver } catch (IOException ex) { 132dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver return false; 133dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver } catch (NotAZipFileException ex) { 134dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver return false; 135e75f2b230a1188ebfeffcb7737dfe94bcc0f9e44Albert Gorski } finally { 136e75f2b230a1188ebfeffcb7737dfe94bcc0f9e44Albert Gorski if(zipFile != null) { 137e75f2b230a1188ebfeffcb7737dfe94bcc0f9e44Albert Gorski try { 138e75f2b230a1188ebfeffcb7737dfe94bcc0f9e44Albert Gorski zipFile.close(); 139e75f2b230a1188ebfeffcb7737dfe94bcc0f9e44Albert Gorski } catch (IOException ex) { 140e75f2b230a1188ebfeffcb7737dfe94bcc0f9e44Albert Gorski // just eat it 141e75f2b230a1188ebfeffcb7737dfe94bcc0f9e44Albert Gorski } 142e75f2b230a1188ebfeffcb7737dfe94bcc0f9e44Albert Gorski } 143dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver } 14431ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver } 14531ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver 14631ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver public class ZipDexFile extends DexBackedDexFile implements MultiDexContainer.MultiDexFile { 14731ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver 14831ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver private final String entryName; 14931ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver 15031ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver protected ZipDexFile(@Nonnull Opcodes opcodes, @Nonnull byte[] buf, @Nonnull String entryName) { 15131ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver super(opcodes, buf, 0); 15231ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver this.entryName = entryName; 15331ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver } 15431ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver 15531ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver @Nonnull @Override public String getEntryName() { 15631ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver return entryName; 15731ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver } 15831ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver 15931ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver @Nonnull @Override public MultiDexContainer getContainer() { 16031ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver return ZipDexContainer.this; 16131ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver } 16231ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver } 16331ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver 164615d3833207dae4c30e559f3aae9dcf074005d49Ben Gruver protected boolean isDex(@Nonnull ZipFile zipFile, @Nonnull ZipEntry zipEntry) throws IOException { 16516d4b5656b0b803689191a299d25237acf735b5bBen Gruver InputStream inputStream = new BufferedInputStream(zipFile.getInputStream(zipEntry)); 16631ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver try { 1674eefe294e4c664577982283cc64c415819a30c1eBen Gruver DexUtil.verifyDexHeader(inputStream); 1684eefe294e4c664577982283cc64c415819a30c1eBen Gruver } catch (NotADexFile ex) { 1694eefe294e4c664577982283cc64c415819a30c1eBen Gruver return false; 1704eefe294e4c664577982283cc64c415819a30c1eBen Gruver } catch (InvalidFile ex) { 1714eefe294e4c664577982283cc64c415819a30c1eBen Gruver return false; 1724eefe294e4c664577982283cc64c415819a30c1eBen Gruver } catch (UnsupportedFile ex) { 1734eefe294e4c664577982283cc64c415819a30c1eBen Gruver return false; 17431ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver } finally { 17531ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver inputStream.close(); 17631ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver } 1774eefe294e4c664577982283cc64c415819a30c1eBen Gruver return true; 17831ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver } 17931ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver 180615d3833207dae4c30e559f3aae9dcf074005d49Ben Gruver protected ZipFile getZipFile() throws IOException { 181dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver try { 182dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver return new ZipFile(zipFilePath); 183dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver } catch (IOException ex) { 184dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver throw new NotAZipFileException(); 185dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver } 186dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver } 187dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver 18831ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver @Nonnull 189615d3833207dae4c30e559f3aae9dcf074005d49Ben Gruver protected ZipDexFile loadEntry(@Nonnull ZipFile zipFile, @Nonnull ZipEntry zipEntry) throws IOException { 19031ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver InputStream inputStream = zipFile.getInputStream(zipEntry); 19131ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver try { 19231ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver byte[] buf = ByteStreams.toByteArray(inputStream); 19331ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver return new ZipDexFile(opcodes, buf, zipEntry.getName()); 19431ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver } finally { 19531ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver inputStream.close(); 19631ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver } 19731ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver } 198dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver 199dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver public static class NotAZipFileException extends RuntimeException { 200dbd9db303a6c30edb00376de2c5ed028a8acc967Ben Gruver } 20131ad2bc1002784161b318627f32b4df8bcb862e0Ben Gruver} 202