1f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson/* 2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Licensed to the Apache Software Foundation (ASF) under one or more 3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * contributor license agreements. See the NOTICE file distributed with 4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * this work for additional information regarding copyright ownership. 5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * The ASF licenses this file to You under the Apache License, Version 2.0 6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * (the "License"); you may not use this file except in compliance with 7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the License. You may obtain a copy of the License at 8f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson * 9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 10f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson * 11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software 12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * See the License for the specific language governing permissions and 15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * limitations under the License. 16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpackage java.util.jar; 19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.File; 21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.FilterInputStream; 22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.IOException; 23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.InputStream; 24f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilsonimport java.util.ArrayList; 25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Enumeration; 261222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamathimport java.util.HashMap; 27f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilsonimport java.util.List; 281222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamathimport java.util.Locale; 29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.zip.ZipEntry; 30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.zip.ZipFile; 316186821cb13f4ac7ff50950c813394367e021eaeJesse Wilsonimport libcore.io.Streams; 32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/** 34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * {@code JarFile} is used to read jar entries and their associated data from 35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * jar files. 3657995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson * 37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see JarInputStream 38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see JarEntry 39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic class JarFile extends ZipFile { 41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * The MANIFEST file name. 44adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 45f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes public static final String MANIFEST_NAME = "META-INF/MANIFEST.MF"; 46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 47f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson // The directory containing the manifest. 48f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes static final String META_DIR = "META-INF/"; 49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 50f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson // The manifest after it has been read from the JAR. 51adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project private Manifest manifest; 52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 531222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath // The entry for the MANIFEST.MF file before the first call to getManifest(). 541222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath private byte[] manifestBytes; 55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project JarVerifier verifier; 57adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project private boolean closed = false; 59adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 60adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project static final class JarFileInputStream extends FilterInputStream { 61913d5005ab8ce6f2542766b67e6486b4e5d1f11fNarayan Kamath private final JarVerifier.VerifierEntry entry; 62adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 63913d5005ab8ce6f2542766b67e6486b4e5d1f11fNarayan Kamath private long count; 64d477459f4b89725dc32043aac8ad6f1dfc93de50Urs Grob private boolean done = false; 65d477459f4b89725dc32043aac8ad6f1dfc93de50Urs Grob 661222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath JarFileInputStream(InputStream is, long size, JarVerifier.VerifierEntry e) { 67adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project super(is); 6857995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson entry = e; 69913d5005ab8ce6f2542766b67e6486b4e5d1f11fNarayan Kamath 701222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath count = size; 71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 72adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 73adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 74adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public int read() throws IOException { 75d477459f4b89725dc32043aac8ad6f1dfc93de50Urs Grob if (done) { 76d477459f4b89725dc32043aac8ad6f1dfc93de50Urs Grob return -1; 77d477459f4b89725dc32043aac8ad6f1dfc93de50Urs Grob } 7857995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson if (count > 0) { 7957995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson int r = super.read(); 80adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (r != -1) { 8157995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson entry.write(r); 82adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project count--; 8357995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson } else { 8457995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson count = 0; 85adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 8657995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson if (count == 0) { 87d477459f4b89725dc32043aac8ad6f1dfc93de50Urs Grob done = true; 8857995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson entry.verify(); 89adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 9057995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson return r; 9157995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson } else { 92d477459f4b89725dc32043aac8ad6f1dfc93de50Urs Grob done = true; 93d477459f4b89725dc32043aac8ad6f1dfc93de50Urs Grob entry.verify(); 9457995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson return -1; 95adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 99325ff8c68ed5e530e9e1d487b9e2e6d8f8e2bd37Elliott Hughes public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException { 100d477459f4b89725dc32043aac8ad6f1dfc93de50Urs Grob if (done) { 101d477459f4b89725dc32043aac8ad6f1dfc93de50Urs Grob return -1; 102d477459f4b89725dc32043aac8ad6f1dfc93de50Urs Grob } 10357995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson if (count > 0) { 104325ff8c68ed5e530e9e1d487b9e2e6d8f8e2bd37Elliott Hughes int r = super.read(buffer, byteOffset, byteCount); 105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (r != -1) { 106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project int size = r; 107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (count < size) { 108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project size = (int) count; 109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 110325ff8c68ed5e530e9e1d487b9e2e6d8f8e2bd37Elliott Hughes entry.write(buffer, byteOffset, size); 11157995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson count -= size; 11257995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson } else { 11357995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson count = 0; 114adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 11557995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson if (count == 0) { 116d477459f4b89725dc32043aac8ad6f1dfc93de50Urs Grob done = true; 11757995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson entry.verify(); 118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 11957995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson return r; 12057995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson } else { 121d477459f4b89725dc32043aac8ad6f1dfc93de50Urs Grob done = true; 122d477459f4b89725dc32043aac8ad6f1dfc93de50Urs Grob entry.verify(); 12357995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson return -1; 12457995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson } 12557995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson } 12657995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson 12757995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson @Override 12857995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson public int available() throws IOException { 129d477459f4b89725dc32043aac8ad6f1dfc93de50Urs Grob if (done) { 13057995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson return 0; 131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 132d477459f4b89725dc32043aac8ad6f1dfc93de50Urs Grob return super.available(); 133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 13680b486724ca19b3c1c3c36334d06856330362f83Jesse Wilson public long skip(long byteCount) throws IOException { 13780b486724ca19b3c1c3c36334d06856330362f83Jesse Wilson return Streams.skipByReading(this, byteCount); 138adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 139adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 140adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 141913d5005ab8ce6f2542766b67e6486b4e5d1f11fNarayan Kamath static final class JarFileEnumerator implements Enumeration<JarEntry> { 142913d5005ab8ce6f2542766b67e6486b4e5d1f11fNarayan Kamath final Enumeration<? extends ZipEntry> ze; 143913d5005ab8ce6f2542766b67e6486b4e5d1f11fNarayan Kamath final JarFile jf; 144913d5005ab8ce6f2542766b67e6486b4e5d1f11fNarayan Kamath 145913d5005ab8ce6f2542766b67e6486b4e5d1f11fNarayan Kamath JarFileEnumerator(Enumeration<? extends ZipEntry> zenum, JarFile jf) { 146913d5005ab8ce6f2542766b67e6486b4e5d1f11fNarayan Kamath ze = zenum; 147913d5005ab8ce6f2542766b67e6486b4e5d1f11fNarayan Kamath this.jf = jf; 148913d5005ab8ce6f2542766b67e6486b4e5d1f11fNarayan Kamath } 149913d5005ab8ce6f2542766b67e6486b4e5d1f11fNarayan Kamath 150913d5005ab8ce6f2542766b67e6486b4e5d1f11fNarayan Kamath public boolean hasMoreElements() { 151913d5005ab8ce6f2542766b67e6486b4e5d1f11fNarayan Kamath return ze.hasMoreElements(); 152913d5005ab8ce6f2542766b67e6486b4e5d1f11fNarayan Kamath } 153913d5005ab8ce6f2542766b67e6486b4e5d1f11fNarayan Kamath 154913d5005ab8ce6f2542766b67e6486b4e5d1f11fNarayan Kamath public JarEntry nextElement() { 155913d5005ab8ce6f2542766b67e6486b4e5d1f11fNarayan Kamath return new JarEntry(ze.nextElement(), jf /* parentJar */); 156913d5005ab8ce6f2542766b67e6486b4e5d1f11fNarayan Kamath } 157913d5005ab8ce6f2542766b67e6486b4e5d1f11fNarayan Kamath } 158913d5005ab8ce6f2542766b67e6486b4e5d1f11fNarayan Kamath 159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Create a new {@code JarFile} using the contents of the specified file. 16157995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson * 162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param file 163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the JAR file as {@link File}. 164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @throws IOException 165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * If the file cannot be read. 166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public JarFile(File file) throws IOException { 168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project this(file, true); 169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Create a new {@code JarFile} using the contents of the specified file. 17357995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson * 174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param file 175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the JAR file as {@link File}. 176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param verify 177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * if this JAR file is signed whether it must be verified. 178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @throws IOException 179adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * If the file cannot be read. 180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public JarFile(File file, boolean verify) throws IOException { 1821222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath this(file, verify, ZipFile.OPEN_READ); 183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Create a new {@code JarFile} using the contents of file. 18757995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson * 188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param file 189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the JAR file as {@link File}. 190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param verify 191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * if this JAR filed is signed whether it must be verified. 192adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param mode 193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the mode to use, either {@link ZipFile#OPEN_READ OPEN_READ} or 194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * {@link ZipFile#OPEN_DELETE OPEN_DELETE}. 195adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @throws IOException 196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * If the file cannot be read. 197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 198adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public JarFile(File file, boolean verify, int mode) throws IOException { 199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project super(file, mode); 2001222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath 2011222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath // Step 1: Scan the central directory for meta entries (MANIFEST.mf 2021222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath // & possibly the signature files) and read them fully. 2031222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath HashMap<String, byte[]> metaEntries = readMetaEntries(this, verify); 2041222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath 2051222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath // Step 2: Construct a verifier with the information we have. 2061222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath // Verification is possible *only* if the JAR file contains a manifest 2071222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath // *AND* it contains signing related information (signature block 2081222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath // files and the signature files). 2091222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath // 2101222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath // TODO: Is this really the behaviour we want if verify == true ? 2111222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath // We silently skip verification for files that have no manifest or 2121222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath // no signatures. 2131222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath if (verify && metaEntries.containsKey(MANIFEST_NAME) && 2141222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath metaEntries.size() > 1) { 2151222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath // We create the manifest straight away, so that we can create 2161222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath // the jar verifier as well. 2171222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath manifest = new Manifest(metaEntries.get(MANIFEST_NAME), true); 218dbb6b44240b9ab10f31824987445ee7c8e1b53a1Kenny Root verifier = new JarVerifier(getName(), manifest, metaEntries); 2191222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath } else { 2201222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath verifier = null; 2211222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath manifestBytes = metaEntries.get(MANIFEST_NAME); 222adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 223adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 224adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 225adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 226adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Create a new {@code JarFile} from the contents of the file specified by 227adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * filename. 22857995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson * 229adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param filename 230adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the file name referring to the JAR file. 231adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @throws IOException 232adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * if file name cannot be opened for reading. 233adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 234adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public JarFile(String filename) throws IOException { 235adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project this(filename, true); 236adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 237adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 238adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 239adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Create a new {@code JarFile} from the contents of the file specified by 240adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * {@code filename}. 24157995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson * 242adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param filename 243adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the file name referring to the JAR file. 244adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param verify 245adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * if this JAR filed is signed whether it must be verified. 246adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @throws IOException 247adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * If file cannot be opened or read. 248adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 249adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public JarFile(String filename, boolean verify) throws IOException { 250dbb6b44240b9ab10f31824987445ee7c8e1b53a1Kenny Root this(new File(filename), verify, ZipFile.OPEN_READ); 251adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 252adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 253adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 254adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Return an enumeration containing the {@code JarEntrys} contained in this 255adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * {@code JarFile}. 25657995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson * 257adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the {@code Enumeration} containing the JAR entries. 258adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @throws IllegalStateException 259adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * if this {@code JarFile} is closed. 260adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 261adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 262adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public Enumeration<JarEntry> entries() { 263adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return new JarFileEnumerator(super.entries(), this); 264adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 265adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 266adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 267adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Return the {@code JarEntry} specified by its name or {@code null} if no 268adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * such entry exists. 26957995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson * 270adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param name 271adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the name of the entry in the JAR file. 272adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the JAR entry defined by the name. 273adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 274adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public JarEntry getJarEntry(String name) { 275adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return (JarEntry) getEntry(name); 276adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 277adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 278adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 279adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns the {@code Manifest} object associated with this {@code JarFile} 280adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * or {@code null} if no MANIFEST entry exists. 28157995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson * 282adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the MANIFEST. 283adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @throws IOException 284adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * if an error occurs reading the MANIFEST file. 285adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @throws IllegalStateException 286adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * if the jar file is closed. 287adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see Manifest 288adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 289adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public Manifest getManifest() throws IOException { 290adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (closed) { 291b1433b3bd4dfc05426e5d9c3100b5fbaa198d8a0Elliott Hughes throw new IllegalStateException("JarFile has been closed"); 292adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 2931222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath 294adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (manifest != null) { 295adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return manifest; 296adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 2971222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath 2981222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath // If manifest == null && manifestBytes == null, there's no manifest. 2991222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath if (manifestBytes == null) { 3001222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath return null; 301adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 3021222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath 3031222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath // We hit this code path only if the verification isn't necessary. If 3041222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath // we did decide to verify this file, we'd have created the Manifest and 3051222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath // the associated Verifier in the constructor itself. 3061222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath manifest = new Manifest(manifestBytes, false); 3071222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath manifestBytes = null; 3081222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath 309adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return manifest; 310adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 311adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 312f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson /** 3131222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath * Called by the JarFile constructors, Reads the contents of the 314f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson * file's META-INF/ directory and picks out the MANIFEST.MF file and 3151222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath * verifier signature files if they exist. 316f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 317f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson * @throws IOException 318f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson * if there is a problem reading the jar file entries. 3191222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath * @return a map of entry names to their {@code byte[]} content. 320f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson */ 3211222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath static HashMap<String, byte[]> readMetaEntries(ZipFile zipFile, 3221222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath boolean verificationRequired) throws IOException { 323f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson // Get all meta directory entries 3241222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath List<ZipEntry> metaEntries = getMetaEntries(zipFile); 325adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 3261222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath HashMap<String, byte[]> metaEntriesMap = new HashMap<String, byte[]>(); 327adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 328f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson for (ZipEntry entry : metaEntries) { 329f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson String entryName = entry.getName(); 330f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson // Is this the entry for META-INF/MANIFEST.MF ? 3311222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath // 3321222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath // TODO: Why do we need the containsKey check ? Shouldn't we discard 3331222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath // files that contain duplicate entries like this as invalid ?. 3341222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath if (entryName.equalsIgnoreCase(MANIFEST_NAME) && 3351222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath !metaEntriesMap.containsKey(MANIFEST_NAME)) { 3361222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath 3371222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath metaEntriesMap.put(MANIFEST_NAME, Streams.readFully( 3381222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath zipFile.getInputStream(entry))); 3391222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath 340f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson // If there is no verifier then we don't need to look any further. 3411222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath if (!verificationRequired) { 342f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson break; 343f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson } 3441222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath } else if (verificationRequired) { 345f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson // Is this an entry that the verifier needs? 3461222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath if (endsWithIgnoreCase(entryName, ".SF") 3471222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath || endsWithIgnoreCase(entryName, ".DSA") 3481222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath || endsWithIgnoreCase(entryName, ".RSA") 3491222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath || endsWithIgnoreCase(entryName, ".EC")) { 3501222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath InputStream is = zipFile.getInputStream(entry); 3511222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath metaEntriesMap.put(entryName.toUpperCase(Locale.US), Streams.readFully(is)); 352adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 353adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 354adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 355f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson 3561222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath return metaEntriesMap; 357adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 358adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 359c729e213248a11cce7a186c559cee78afff91837Jesse Wilson private static boolean endsWithIgnoreCase(String s, String suffix) { 360c729e213248a11cce7a186c559cee78afff91837Jesse Wilson return s.regionMatches(true, s.length() - suffix.length(), suffix, 0, suffix.length()); 361c729e213248a11cce7a186c559cee78afff91837Jesse Wilson } 362c729e213248a11cce7a186c559cee78afff91837Jesse Wilson 363adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 364adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Return an {@code InputStream} for reading the decompressed contents of 365adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * ZIP entry. 36657995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson * 367adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param ze 368adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the ZIP entry to be read. 369adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the input stream to read from. 370adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @throws IOException 371adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * if an error occurred while creating the input stream. 372adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 373adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 374adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public InputStream getInputStream(ZipEntry ze) throws IOException { 3751222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath if (manifestBytes != null) { 376adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project getManifest(); 377adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 3781222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath 379adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (verifier != null) { 380adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (verifier.readCertificates()) { 381adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project verifier.removeMetaEntries(); 3821222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath manifest.removeChunks(); 3831222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath 384adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (!verifier.isSignedJar()) { 385adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project verifier = null; 386adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 387adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 388adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 3891222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath 390adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project InputStream in = super.getInputStream(ze); 391adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (in == null) { 392adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return null; 393adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 39457995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson if (verifier == null || ze.getSize() == -1) { 39557995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson return in; 39657995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson } 39757995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson JarVerifier.VerifierEntry entry = verifier.initEntry(ze.getName()); 39857995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson if (entry == null) { 39957995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson return in; 40057995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson } 4011222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath return new JarFileInputStream(in, ze.getSize(), entry); 402adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 403adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 404adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 405adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Return the {@code JarEntry} specified by name or {@code null} if no such 406adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * entry exists. 40757995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson * 408adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param name 409adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the name of the entry in the JAR file. 410adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the ZIP entry extracted. 41157995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson */ 412adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 413adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public ZipEntry getEntry(String name) { 414adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project ZipEntry ze = super.getEntry(name); 415adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (ze == null) { 416adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return ze; 417adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 418913d5005ab8ce6f2542766b67e6486b4e5d1f11fNarayan Kamath return new JarEntry(ze, this /* parentJar */); 419adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 420adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 421f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson /** 422f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson * Returns all the ZipEntry's that relate to files in the 423f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson * JAR's META-INF directory. 424f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson */ 4251222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath private static List<ZipEntry> getMetaEntries(ZipFile zipFile) { 426f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson List<ZipEntry> list = new ArrayList<ZipEntry>(8); 4271222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath 4281222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath Enumeration<? extends ZipEntry> allEntries = zipFile.entries(); 429adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project while (allEntries.hasMoreElements()) { 430adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project ZipEntry ze = allEntries.nextElement(); 431f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson if (ze.getName().startsWith(META_DIR) 432f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson && ze.getName().length() > META_DIR.length()) { 433adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project list.add(ze); 434adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 435adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 4361222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath 4371222b64d823e028efa6f02b08a55d788bfd57b16Narayan Kamath return list; 438adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 439adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 440adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 441adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Closes this {@code JarFile}. 44257995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson * 443adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @throws IOException 444adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * if an error occurs. 445adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 446adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 447adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public void close() throws IOException { 448adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project super.close(); 449adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project closed = true; 450adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 451adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 452