1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * you may not use this file except in compliance with the License.
6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * You may obtain a copy of the License at
7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * See the License for the specific language governing permissions and
14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * limitations under the License.
15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
16f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpackage com.android.dx.cf.direct;
18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
19fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport com.android.dex.util.FileUtils;
203abdb48fdefcc3136a8d7f9c168a305d9be9690eYohann Roussel
21fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport java.io.ByteArrayOutputStream;
22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.File;
23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.IOException;
24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.InputStream;
25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.ArrayList;
26fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport java.util.Arrays;
27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.Collections;
28fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport java.util.Comparator;
29fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport java.util.zip.ZipEntry;
30fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport java.util.zip.ZipFile;
31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/**
33f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Opens all the class files found in a class path element. Path elements
34f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * can point to class files, {jar,zip,apk} files, or directories containing
35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * class files.
36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpublic class ClassPathOpener {
38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code non-null;} pathname to start with */
40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final String pathname;
4199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code non-null;} callback interface */
42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final Consumer consumer;
43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
44f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * If true, sort such that classes appear before their inner
45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * classes and "package-info" occurs before all other classes in that
46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * package.
47f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final boolean sort;
494c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche    private FileNameFilter filter;
50f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
5299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * Callback interface for {@code ClassOpener}.
53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public interface Consumer {
55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
56f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Provides the file name and byte array for a class path element.
58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         *
5999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * @param name {@code non-null;} filename of element. May not be a valid
60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * filesystem path.
61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         *
62dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson         * @param lastModified milliseconds since 1970-Jan-1 00:00:00 GMT
6399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * @param bytes {@code non-null;} file data
64f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * @return true on success. Result is or'd with all other results
6599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * from {@code processFileBytes} and returned to the caller
6699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * of {@code process()}.
67f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
68dc86cd9edc8b80953c8b698a83cdaebf6825d798Jesse Wilson        boolean processFileBytes(String name, long lastModified, byte[] bytes);
69f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
70f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Informs consumer that an exception occurred while processing
72f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * this path element. Processing will continue if possible.
73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         *
7499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * @param ex {@code non-null;} exception
75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
76f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        void onException(Exception ex);
77f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
79f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Informs consumer that processing of an archive file has begun.
80f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         *
8199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * @param file {@code non-null;} archive file being processed
82f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
83f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        void onProcessArchiveStart(File file);
84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
874c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche     * Filter interface for {@code ClassOpener}.
884c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche     */
894c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche    public interface FileNameFilter {
904c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche
914c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche        boolean accept(String path);
924c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche    }
934c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche
944c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche    /**
954c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche     * An accept all filter.
964c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche     */
974c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche    public static final FileNameFilter acceptAll = new FileNameFilter() {
984c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche
994c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche        @Override
1004c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche        public boolean accept(String path) {
1014c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche            return true;
1024c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche        }
1034c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche    };
1044c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche
1054c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche    /**
106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Constructs an instance.
107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
10899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param pathname {@code non-null;} path element to process
109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param sort if true, sort such that classes appear before their inner
110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * classes and "package-info" occurs before all other classes in that
111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * package.
11299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param consumer {@code non-null;} callback interface
113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public ClassPathOpener(String pathname, boolean sort, Consumer consumer) {
1154c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche        this(pathname, sort, acceptAll, consumer);
1164c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche    }
1174c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche
1184c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche    /**
1194c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche     * Constructs an instance.
1204c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche     *
1214c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche     * @param pathname {@code non-null;} path element to process
1224c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche     * @param sort if true, sort such that classes appear before their inner
1234c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche     * classes and "package-info" occurs before all other classes in that
1244c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche     * package.
1254c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche     * @param consumer {@code non-null;} callback interface
1264c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche     */
1274c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche    public ClassPathOpener(String pathname, boolean sort, FileNameFilter filter,
1284c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche            Consumer consumer) {
129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.pathname = pathname;
130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.sort = sort;
131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.consumer = consumer;
1324c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche        this.filter = filter;
133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Processes a path element.
137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return the OR of all return values
13999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * from {@code Consumer.processFileBytes()}.
140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public boolean process() {
142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        File file = new File(pathname);
143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return processOne(file, true);
145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Processes one file.
149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
15099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param file {@code non-null;} the file to process
151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param topLevel whether this is a top-level file (that is,
152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * specified directly on the commandline)
153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return whether any processing actually happened
154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private boolean processOne(File file, boolean topLevel) {
156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        try {
157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (file.isDirectory()) {
158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                return processDirectory(file, topLevel);
159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            String path = file.getPath();
162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (path.endsWith(".zip") ||
164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    path.endsWith(".jar") ||
165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    path.endsWith(".apk")) {
166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                return processArchive(file);
167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1684c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche            if (filter.accept(path)) {
1694c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche                byte[] bytes = FileUtils.readFile(file);
1704c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche                return consumer.processFileBytes(path, file.lastModified(), bytes);
1714c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche            } else {
1724c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche                return false;
1734c656e4ec2f5c5036dc67fb4034c1e7ff7abf343Benoit Lamarche            }
174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } catch (Exception ex) {
175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            consumer.onException(ex);
176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return false;
177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Sorts java class names such that outer classes preceed their inner
182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * classes and "package-info" preceeds all other classes in its package.
183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
18499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param a {@code non-null;} first class name
18599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param b {@code non-null;} second class name
18699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code compareTo()}-style result
187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static int compareClassNames(String a, String b) {
189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // Ensure inner classes sort second
190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        a = a.replace('$','0');
191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        b = b.replace('$','0');
192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Assuming "package-info" only occurs at the end, ensures package-info
195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * sorts first.
196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        a = a.replace("package-info", "");
198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        b = b.replace("package-info", "");
199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return a.compareTo(b);
201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Processes a directory recursively.
205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
20699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param dir {@code non-null;} file representing the directory
207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param topLevel whether this is a top-level directory (that is,
208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * specified directly on the commandline)
209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return whether any processing actually happened
210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private boolean processDirectory(File dir, boolean topLevel) {
212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (topLevel) {
213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            dir = new File(dir, ".");
214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        File[] files = dir.listFiles();
217f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int len = files.length;
218f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        boolean any = false;
219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
220f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (sort) {
221f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Arrays.sort(files, new Comparator<File>() {
222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                public int compare(File a, File b) {
223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    return compareClassNames(a.getName(), b.getName());
224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
225f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            });
226f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
227f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
228f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < len; i++) {
229f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            any |= processOne(files[i], false);
230f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
231f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
232f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return any;
233f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
234f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
23699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * Processes the contents of an archive ({@code .zip},
23799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code .jar}, or {@code .apk}).
238f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
23999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param file {@code non-null;} archive file to process
240f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return whether any processing actually happened
241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @throws IOException on i/o problem
242f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private boolean processArchive(File file) throws IOException {
244f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        ZipFile zip = new ZipFile(file);
245f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
246de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro        ArrayList<? extends java.util.zip.ZipEntry> entriesList
247f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                = Collections.list(zip.entries());
248f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
249f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (sort) {
250f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Collections.sort(entriesList, new Comparator<ZipEntry>() {
251f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project               public int compare (ZipEntry a, ZipEntry b) {
252f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                   return compareClassNames(a.getName(), b.getName());
253f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project               }
254f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            });
255f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
256f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
257f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        consumer.onProcessArchiveStart(file);
258f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2597736e8ff04c2974edd9de9ca150f12dc601b005dNarayan Kamath        ByteArrayOutputStream baos = new ByteArrayOutputStream(40000);
2607736e8ff04c2974edd9de9ca150f12dc601b005dNarayan Kamath        byte[] buf = new byte[20000];
2617736e8ff04c2974edd9de9ca150f12dc601b005dNarayan Kamath        boolean any = false;
2627736e8ff04c2974edd9de9ca150f12dc601b005dNarayan Kamath
26341aecd0a6bfea1e9a6713014b2b3d56fec8c552cDan Bornstein        for (ZipEntry one : entriesList) {
2647736e8ff04c2974edd9de9ca150f12dc601b005dNarayan Kamath            final boolean isDirectory = one.isDirectory();
265f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
266f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            String path = one.getName();
2673abdb48fdefcc3136a8d7f9c168a305d9be9690eYohann Roussel            if (filter.accept(path)) {
2687736e8ff04c2974edd9de9ca150f12dc601b005dNarayan Kamath                final byte[] bytes;
2697736e8ff04c2974edd9de9ca150f12dc601b005dNarayan Kamath                if (!isDirectory) {
2707736e8ff04c2974edd9de9ca150f12dc601b005dNarayan Kamath                    InputStream in = zip.getInputStream(one);
2717736e8ff04c2974edd9de9ca150f12dc601b005dNarayan Kamath
2727736e8ff04c2974edd9de9ca150f12dc601b005dNarayan Kamath                    baos.reset();
2737736e8ff04c2974edd9de9ca150f12dc601b005dNarayan Kamath                    int read;
2747736e8ff04c2974edd9de9ca150f12dc601b005dNarayan Kamath                    while ((read = in.read(buf)) != -1) {
2757736e8ff04c2974edd9de9ca150f12dc601b005dNarayan Kamath                        baos.write(buf, 0, read);
2763abdb48fdefcc3136a8d7f9c168a305d9be9690eYohann Roussel                    }
277f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2787736e8ff04c2974edd9de9ca150f12dc601b005dNarayan Kamath                    in.close();
2797736e8ff04c2974edd9de9ca150f12dc601b005dNarayan Kamath                    bytes = baos.toByteArray();
2807736e8ff04c2974edd9de9ca150f12dc601b005dNarayan Kamath                } else {
2817736e8ff04c2974edd9de9ca150f12dc601b005dNarayan Kamath                    bytes = new byte[0];
2823abdb48fdefcc3136a8d7f9c168a305d9be9690eYohann Roussel                }
283f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2843abdb48fdefcc3136a8d7f9c168a305d9be9690eYohann Roussel                any |= consumer.processFileBytes(path, one.getTime(), bytes);
2853abdb48fdefcc3136a8d7f9c168a305d9be9690eYohann Roussel            }
286f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
287f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
288f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        zip.close();
289f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return any;
290f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
291f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
292