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