Main.java revision 1e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3b
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.command.dexer;
18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.Version;
20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.cf.iface.ParseException;
21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.cf.direct.ClassPathOpener;
22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.command.DxConsole;
23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.command.UsageException;
24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.dex.cf.CfOptions;
25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.dex.cf.CfTranslator;
26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.dex.cf.CodeStatistics;
27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.dex.code.PositionList;
28f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.dex.file.ClassDefItem;
29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.dex.file.DexFile;
30f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.dex.file.EncodedMethod;
31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.annotation.Annotation;
32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.annotation.Annotations;
33f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.annotation.AnnotationsList;
34f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.CstNat;
35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.CstUtf8;
36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.ByteArrayInputStream;
38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.File;
39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.FileOutputStream;
40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.IOException;
41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.OutputStream;
42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.OutputStreamWriter;
43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.PrintWriter;
44f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.Arrays;
45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.ArrayList;
46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.Map;
47f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.TreeMap;
48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.jar.Attributes;
49f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.jar.JarEntry;
50f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.jar.JarOutputStream;
51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.jar.Manifest;
52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/**
54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Main class for the class file translator.
55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
56f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpublic class Main {
57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
5885dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein     * {@code non-null;} the lengthy message that tries to discourage
5985dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein     * people from defining core classes in applications
6085dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein     */
6185dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein    private static final String IN_RE_CORE_CLASSES =
6285dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "Ill-advised or mistaken usage of a core class (java.* or javax.*)\n" +
6385dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "when not building a core library.\n\n" +
6485dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "This is often due to inadvertently including a core library file\n" +
6585dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "in your application's project, when using an IDE (such as\n" +
6685dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "Eclipse). If you are sure you're not intentionally defining a\n" +
6785dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "core class, then this is the most likely explanation of what's\n" +
6885dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "going on.\n\n" +
6985dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "However, you might actually be trying to define a class in a core\n" +
7085dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "namespace, the source of which you may have taken, for example,\n" +
7185dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "from a non-Android virtual machine project. This will most\n" +
7285dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "assuredly not work. At a minimum, it jeopardizes the\n" +
7385dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "compatibility of your app with future versions of the platform.\n" +
7485dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "It is also often of questionable legality.\n\n" +
7585dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "If you really intend to build a core library -- which is only\n" +
7685dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "appropriate as part of creating a full virtual machine\n" +
7785dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "distribution, as opposed to compiling an application -- then use\n" +
7885dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "the \"--core-library\" option to suppress this error message.\n\n" +
7985dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "If you go ahead and use \"--core-library\" but are in fact\n" +
8085dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "building an application, then be forewarned that your application\n" +
8185dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "will still fail to build or run, at some point. Please be\n" +
8285dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "prepared for angry customers who find, for example, that your\n" +
8385dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "application ceases to function once they upgrade their operating\n" +
8485dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "system. You will be to blame for this problem.\n\n" +
8585dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "If you are legitimately using some code that happens to be in a\n" +
8685dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "core package, then the easiest safe alternative you have is to\n" +
8785dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "repackage that code. That is, move the classes in question into\n" +
8885dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "your own package namespace. This means that they will never be in\n" +
8985dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "conflict with core system classes. JarJar is a tool that may help\n" +
9085dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "you in this endeavor. If you find that you cannot do this, then\n" +
9185dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "that is an indication that the path you are on will ultimately\n" +
9285dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        "lead to pain, suffering, grief, and lamentation.\n";
9385dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein
9485dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein    /**
9599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code non-null;} name for the {@code .dex} file that goes into
9699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code .jar} files
97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static final String DEX_IN_JAR_NAME = "classes.dex";
99f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
10199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code non-null;} name of the standard manifest file in {@code .jar}
102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * files
103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static final String MANIFEST_NAME = "META-INF/MANIFEST.MF";
105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
10799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code non-null;} attribute name for the (quasi-standard?)
10899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code Created-By} attribute
109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static final Attributes.Name CREATED_BY =
111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        new Attributes.Name("Created-By");
112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
11499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code non-null;} list of {@code javax} subpackages that are considered
115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * to be "core". <b>Note:</b>: This list must be sorted, since it
116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * is binary-searched.
117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static final String[] JAVAX_CORE = {
119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        "accessibility", "crypto", "imageio", "management", "naming", "net",
120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        "print", "rmi", "security", "sound", "sql", "swing", "transaction",
121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        "xml"
122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    };
123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** number of warnings during processing */
125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static int warnings = 0;
126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** number of errors during processing */
128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static int errors = 0;
129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
13099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code non-null;} parsed command-line arguments */
131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static Arguments args;
132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
13399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code non-null;} output file in-progress */
134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static DexFile outputDex;
135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
13799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code null-ok;} map of resources to include in the output, or
13899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code null} if resources are being ignored
139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static TreeMap<String, byte[]> outputResources;
141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * This class is uninstantiable.
144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private Main() {
146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // This space intentionally left blank.
147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Run and exit if something unexpected happened.
151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param argArray the command line arguments
152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public static void main(String[] argArray) {
154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Arguments arguments = new Arguments();
155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        arguments.parse(argArray);
156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int result = run(arguments);
158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (result != 0) {
159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            System.exit(result);
160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Run and return a result code.
165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param arguments the data + parameters for the conversion
166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return 0 if success > 0 otherwise.
167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public static int run(Arguments arguments) {
169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // Reset the error/warning count to start fresh.
170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        warnings = 0;
171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        errors = 0;
172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        args = arguments;
174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        args.makeCfOptions();
175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (!processAllFiles()) {
177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return 1;
178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[] outArray = writeDex();
181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (outArray == null) {
183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return 2;
184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (args.jarOutput) {
187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // Effectively free up the (often massive) DexFile memory.
188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            outputDex = null;
189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (!createJar(args.outName, outArray)) {
191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                return 3;
192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return 0;
196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Constructs the output {@link DexFile}, fill it in with all the
200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * specified classes, and populate the resources map if required.
201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return whether processing was successful
203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static boolean processAllFiles() {
205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        outputDex = new DexFile();
206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (args.jarOutput) {
208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            outputResources = new TreeMap<String, byte[]>();
209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (args.dumpWidth != 0) {
212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            outputDex.setDumpWidth(args.dumpWidth);
213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        boolean any = false;
216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        String[] fileNames = args.fileNames;
217f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
218f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        try {
219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            for (int i = 0; i < fileNames.length; i++) {
220f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                any |= processOne(fileNames[i]);
221f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } catch (StopProcessing ex) {
223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * Ignore it and just let the warning/error reporting do
225f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * their things.
226f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
227f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
228f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
229f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (warnings != 0) {
230f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            DxConsole.err.println(warnings + " warning" +
231f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                               ((warnings == 1) ? "" : "s"));
232f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
233f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
234f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (errors != 0) {
235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            DxConsole.err.println(errors + " error" +
236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    ((errors == 1) ? "" : "s") + "; aborting");
237f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return false;
238f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
239f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
240f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (!(any || args.emptyOk)) {
241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            DxConsole.err.println("no classfiles specified");
242f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return false;
243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
244f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
245f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (args.optimize && args.statistics) {
246f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            CodeStatistics.dumpStatistics(DxConsole.out);
247f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
248f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
249f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return true;
250f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
251f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
252f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
253f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Processes one pathname element.
254f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
25555423dcd081e30c4fc27b997f127db7b00f1b981Dan Bornstein     * @param pathname {@code non-null;} the pathname to process. May
25655423dcd081e30c4fc27b997f127db7b00f1b981Dan Bornstein     * be the path of a class file, a jar file, or a directory
25755423dcd081e30c4fc27b997f127db7b00f1b981Dan Bornstein     * containing class files.
258f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return whether any processing actually happened
259f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
260f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static boolean processOne(String pathname) {
261f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        ClassPathOpener opener;
262f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
263f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        opener = new ClassPathOpener(pathname, false,
264f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                new ClassPathOpener.Consumer() {
265f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            public boolean processFileBytes(String name, byte[] bytes) {
266f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                return Main.processFileBytes(name, bytes);
267f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
268f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            public void onException(Exception ex) {
269f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (ex instanceof StopProcessing) {
270f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    throw (StopProcessing) ex;
271f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
272f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                DxConsole.err.println("\nUNEXPECTED TOP-LEVEL EXCEPTION:");
273f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                ex.printStackTrace(DxConsole.err);
274f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                errors++;
275f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
276f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            public void onProcessArchiveStart(File file) {
277f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (args.verbose) {
27855423dcd081e30c4fc27b997f127db7b00f1b981Dan Bornstein                    DxConsole.out.println("processing archive " + file +
27955423dcd081e30c4fc27b997f127db7b00f1b981Dan Bornstein                            "...");
280f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
281f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
282f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        });
283f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
284de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro        return opener.process();
285f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
286f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
287f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
288f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Processes one file, which may be either a class or a resource.
289f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
29099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param name {@code non-null;} name of the file
29199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param bytes {@code non-null;} contents of the file
292f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return whether processing was successful
293f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
294f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static boolean processFileBytes(String name, byte[] bytes) {
295f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        boolean isClass = name.endsWith(".class");
296f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        boolean keepResources = (outputResources != null);
297f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
298f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (!isClass && !keepResources) {
299f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (args.verbose) {
300f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                DxConsole.out.println("ignored resource " + name);
301f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
302f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return false;
303f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
304f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
305f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (args.verbose) {
306f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            DxConsole.out.println("processing " + name + "...");
307f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
308f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
309f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        String fixedName = fixPath(name);
310f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
311f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (isClass) {
312f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (keepResources && args.keepClassesInJar) {
313f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                outputResources.put(fixedName, bytes);
314f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
315f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return processClass(fixedName, bytes);
316f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
317f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            outputResources.put(fixedName, bytes);
318f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return true;
319f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
320f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
321f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
322f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
323f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Processes one classfile.
324f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
32599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param name {@code non-null;} name of the file, clipped such that it
326f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * <i>should</i> correspond to the name of the class it contains
32799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param bytes {@code non-null;} contents of the file
328f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return whether processing was successful
329f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
330f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static boolean processClass(String name, byte[] bytes) {
331f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (! args.coreLibrary) {
332f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            checkClassName(name);
333f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
334de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro
335f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        try {
336f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ClassDefItem clazz =
337f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                CfTranslator.translate(name, bytes, args.cfOptions);
338f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            outputDex.add(clazz);
339f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return true;
340f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } catch (ParseException ex) {
341f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            DxConsole.err.println("\ntrouble processing:");
342f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (args.debug) {
343f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                ex.printStackTrace(DxConsole.err);
344f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
345f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                ex.printContext(DxConsole.err);
346f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
347f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
348f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
349f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        warnings++;
350f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return false;
351f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
352f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
353f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
354f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Check the class name to make sure it's not a "core library"
355f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * class. If there is a problem, this updates the error count and
356f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * throws an exception to stop processing.
357de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
35855423dcd081e30c4fc27b997f127db7b00f1b981Dan Bornstein     * @param name {@code non-null;} the fully-qualified internal-form
35955423dcd081e30c4fc27b997f127db7b00f1b981Dan Bornstein     * class name
360f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
361f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static void checkClassName(String name) {
362f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        boolean bogus = false;
363de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro
364f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (name.startsWith("java/")) {
365f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            bogus = true;
366f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else if (name.startsWith("javax/")) {
367f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int slashAt = name.indexOf('/', 6);
368f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (slashAt == -1) {
369f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                // Top-level javax classes are verboten.
370f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                bogus = true;
371f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
372f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                String pkg = name.substring(6, slashAt);
373f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                bogus = (Arrays.binarySearch(JAVAX_CORE, pkg) >= 0);
374f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
375f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
376f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
377f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (! bogus) {
378f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return;
379f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
380f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
381f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
382f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * The user is probably trying to include an entire desktop
383f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * core library in a misguided attempt to get their application
384f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * working. Try to help them understand what's happening.
385f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
386f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
38785dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein        DxConsole.err.println("\ntrouble processing \"" + name + "\":\n\n" +
38885dc40d2a0cb19792bf3ee6f6c57fed08eb91ea4Dan Bornstein                IN_RE_CORE_CLASSES);
389f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        errors++;
390f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        throw new StopProcessing();
391f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
392f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
393f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
39499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * Converts {@link #outputDex} into a {@code byte[]}, write
395f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * it out to the proper file (if any), and also do whatever human-oriented
396f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * dumping is required.
397f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
39899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code null-ok;} the converted {@code byte[]} or {@code null}
399f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * if there was a problem
400f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
401f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static byte[] writeDex() {
402f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[] outArray = null;
403f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
404f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        try {
405f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            OutputStream out = null;
406f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            OutputStream humanOutRaw = null;
407f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            OutputStreamWriter humanOut = null;
408f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            try {
409f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (args.humanOutName != null) {
410f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    humanOutRaw = openOutput(args.humanOutName);
411f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    humanOut = new OutputStreamWriter(humanOutRaw);
412f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
413f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
414f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (args.methodToDump != null) {
415f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    /*
416f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                     * Simply dump the requested method. Note: The call
417f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                     * to toDex() is required just to get the underlying
418f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                     * structures ready.
419f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                     */
420f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    outputDex.toDex(null, false);
421f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    dumpMethod(outputDex, args.methodToDump, humanOut);
422f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                } else {
423f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    /*
424f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                     * This is the usual case: Create an output .dex file,
425f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                     * and write it, dump it, etc.
426f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                     */
427f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    outArray = outputDex.toDex(humanOut, args.verboseDump);
428f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
429f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    if ((args.outName != null) && !args.jarOutput) {
430f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        out = openOutput(args.outName);
431f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        out.write(outArray);
432f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
433f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
434f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
435f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (args.statistics) {
436f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    DxConsole.out.println(outputDex.getStatistics().toHuman());
437f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
438f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } finally {
439f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (humanOut != null) {
440f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    humanOut.flush();
441f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
442f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                closeOutput(out);
443f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                closeOutput(humanOutRaw);
444f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
445f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } catch (Exception ex) {
446f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (args.debug) {
447f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                DxConsole.err.println("\ntrouble writing output:");
448f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                ex.printStackTrace(DxConsole.err);
449f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
450f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                DxConsole.err.println("\ntrouble writing output: " +
451f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                   ex.getMessage());
452f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
453f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return null;
454f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
455f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
456f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return outArray;
457f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
458f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
459f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
460f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Creates a jar file from the resources and given dex file array.
461f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
46299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param fileName {@code non-null;} name of the file
46355423dcd081e30c4fc27b997f127db7b00f1b981Dan Bornstein     * @param dexArray {@code non-null;} array containing the dex file
46455423dcd081e30c4fc27b997f127db7b00f1b981Dan Bornstein     * to include
465f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return whether the creation was successful
466f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
467f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static boolean createJar(String fileName, byte[] dexArray) {
468f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
469f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Make or modify the manifest (as appropriate), put the dex
470f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * array into the resources map, and then process the entire
471f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * resources map in a uniform manner.
472f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
473f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
474f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        try {
475f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Manifest manifest = makeManifest();
476f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            OutputStream out = openOutput(fileName);
477f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            JarOutputStream jarOut = new JarOutputStream(out, manifest);
478f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
479f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            outputResources.put(DEX_IN_JAR_NAME, dexArray);
480f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
481f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            try {
482f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                for (Map.Entry<String, byte[]> e :
483f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                         outputResources.entrySet()) {
484f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    String name = e.getKey();
485f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    byte[] contents = e.getValue();
486f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    JarEntry entry = new JarEntry(name);
487f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
488f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    if (args.verbose) {
489f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        DxConsole.out.println("writing " + name + "; size " +
490f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                           contents.length + "...");
491f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
492f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
493f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    entry.setSize(contents.length);
494f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    jarOut.putNextEntry(entry);
495f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    jarOut.write(contents);
496f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    jarOut.closeEntry();
497f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
498f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } finally {
499f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                jarOut.finish();
500f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                jarOut.flush();
501f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                closeOutput(out);
502f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
503f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } catch (Exception ex) {
504f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (args.debug) {
505f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                DxConsole.err.println("\ntrouble writing output:");
506f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                ex.printStackTrace(DxConsole.err);
507f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
508f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                DxConsole.err.println("\ntrouble writing output: " +
509f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                   ex.getMessage());
510f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
511f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return false;
512f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
513f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
514f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return true;
515f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
516f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
517f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
518f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Creates and returns the manifest to use for the output. This may
519f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * modify {@link #outputResources} (removing the pre-existing manifest).
520f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
52199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} the manifest
522f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
523f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static Manifest makeManifest() throws IOException {
524f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[] manifestBytes = outputResources.get(MANIFEST_NAME);
525f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Manifest manifest;
526f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Attributes attribs;
527f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
528f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (manifestBytes == null) {
529f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // We need to construct an entirely new manifest.
530f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            manifest = new Manifest();
531f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            attribs = manifest.getMainAttributes();
532f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            attribs.put(Attributes.Name.MANIFEST_VERSION, "1.0");
533f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
534f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            manifest = new Manifest(new ByteArrayInputStream(manifestBytes));
535f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            attribs = manifest.getMainAttributes();
536f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            outputResources.remove(MANIFEST_NAME);
537f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
538f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
539f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        String createdBy = attribs.getValue(CREATED_BY);
540f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (createdBy == null) {
541f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            createdBy = "";
542f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
543f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            createdBy += " + ";
544f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
545f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        createdBy += "dx " + Version.VERSION;
546f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
547f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        attribs.put(CREATED_BY, createdBy);
548f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        attribs.putValue("Dex-Location", DEX_IN_JAR_NAME);
549f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
550f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return manifest;
551f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
552f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
553f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
554f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Opens and returns the named file for writing, treating "-" specially.
555f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
55699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param name {@code non-null;} the file name
55799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} the opened file
558f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
559f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static OutputStream openOutput(String name) throws IOException {
560f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (name.equals("-") ||
561f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                name.startsWith("-.")) {
562f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return System.out;
563f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
564f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
565f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return new FileOutputStream(name);
566f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
567f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
568f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
569f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Flushes and closes the given output stream, except if it happens to be
570f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * {@link System#out} in which case this method does the flush but not
571f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * the close. This method will also silently do nothing if given a
57299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code null} argument.
573f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
57499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param stream {@code null-ok;} what to close
575f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
576f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static void closeOutput(OutputStream stream) throws IOException {
577f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (stream == null) {
578f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return;
579f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
580f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
581f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        stream.flush();
582f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
583f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (stream != System.out) {
584f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            stream.close();
585f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
586f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
587f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
588f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
589f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Returns the "fixed" version of a given file path, suitable for
59099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * use as a path within a {@code .jar} file and for checking
591f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * against a classfile-internal "this class" name. This looks for
59299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * the last instance of the substring {@code "/./"} within
593f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * the path, and if it finds it, it takes the portion after to be
594f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * the fixed path. If that isn't found but the path starts with
59599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code "./"}, then that prefix is removed and the rest is
596f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * return. If neither of these is the case, this method returns
597f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * its argument.
598f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
59999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param path {@code non-null;} the path to "fix"
60099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} the fixed version (which might be the same as
60199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * the given {@code path})
602f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
603f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static String fixPath(String path) {
604f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
605f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * If the path separator is \ (like on windows), we convert the
606f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * path to a standard '/' separated path.
607f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
608f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (File.separatorChar == '\\') {
609f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            path = path.replace('\\', '/');
610f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
611f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
612f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int index = path.lastIndexOf("/./");
613f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
614f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (index != -1) {
615f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return path.substring(index + 3);
616f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
617f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
618f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (path.startsWith("./")) {
619f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return path.substring(2);
620f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
621f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
622f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return path;
623f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
624f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
625f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
626f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Dumps any method with the given name in the given file.
627f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
62899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param dex {@code non-null;} the dex file
62955423dcd081e30c4fc27b997f127db7b00f1b981Dan Bornstein     * @param fqName {@code non-null;} the fully-qualified name of the
63055423dcd081e30c4fc27b997f127db7b00f1b981Dan Bornstein     * method(s)
63199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param out {@code non-null;} where to dump to
632f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
633f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static void dumpMethod(DexFile dex, String fqName,
634f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            OutputStreamWriter out) {
635f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        boolean wildcard = fqName.endsWith("*");
636f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int lastDot = fqName.lastIndexOf('.');
637f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
638f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if ((lastDot <= 0) || (lastDot == (fqName.length() - 1))) {
639f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            DxConsole.err.println("bogus fully-qualified method name: " +
640f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                               fqName);
641f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return;
642f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
643f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
644f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        String className = fqName.substring(0, lastDot).replace('.', '/');
645f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        String methodName = fqName.substring(lastDot + 1);
646f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        ClassDefItem clazz = dex.getClassOrNull(className);
647f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
648f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (clazz == null) {
649f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            DxConsole.err.println("no such class: " + className);
650f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return;
651f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
652f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
653f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (wildcard) {
654f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            methodName = methodName.substring(0, methodName.length() - 1);
655f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
656f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
657f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        ArrayList<EncodedMethod> allMeths = clazz.getMethods();
658f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        TreeMap<CstNat, EncodedMethod> meths =
659f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            new TreeMap<CstNat, EncodedMethod>();
660f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
661f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
662f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Figure out which methods to include in the output, and get them
663f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * all sorted, so that the printout code is robust with respect to
664f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * changes in the underlying order.
665f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
666f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (EncodedMethod meth : allMeths) {
667f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            String methName = meth.getName().getString();
668f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if ((wildcard && methName.startsWith(methodName)) ||
669f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                (!wildcard && methName.equals(methodName))) {
670f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                meths.put(meth.getRef().getNat(), meth);
671f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
672f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
673f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
674f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (meths.size() == 0) {
675f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            DxConsole.err.println("no such method: " + fqName);
676f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return;
677f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
678f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
679f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        PrintWriter pw = new PrintWriter(out);
680f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
681f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (EncodedMethod meth : meths.values()) {
682f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // TODO: Better stuff goes here, perhaps.
683f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            meth.debugPrint(pw, args.verboseDump);
684f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
685f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
686de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro             * The (default) source file is an attribute of the class, but
687f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * it's useful to see it in method dumps.
688f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
689f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            CstUtf8 sourceFile = clazz.getSourceFile();
690f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (sourceFile != null) {
691f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                pw.println("  source file: " + sourceFile.toQuoted());
692f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
693f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
694f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Annotations methodAnnotations =
695f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                clazz.getMethodAnnotations(meth.getRef());
696f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            AnnotationsList parameterAnnotations =
697f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                clazz.getParameterAnnotations(meth.getRef());
698f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
699f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (methodAnnotations != null) {
700f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                pw.println("  method annotations:");
701f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                for (Annotation a : methodAnnotations.getAnnotations()) {
702f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    pw.println("    " + a);
703f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
704f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
705f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
706f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (parameterAnnotations != null) {
707f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                pw.println("  parameter annotations:");
708f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                int sz = parameterAnnotations.size();
709f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                for (int i = 0; i < sz; i++) {
710f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    pw.println("    parameter " + i);
711f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    Annotations annotations = parameterAnnotations.get(i);
712f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    for (Annotation a : annotations.getAnnotations()) {
713f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        pw.println("      " + a);
714f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
715f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
716f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
717f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
718f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
719f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        pw.flush();
720f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
721f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
722f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
723f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Exception class used to halt processing prematurely.
724f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
725f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static class StopProcessing extends RuntimeException {
726f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // This space intentionally left blank.
727f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
728de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro
729f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
730f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Command-line argument parser and access.
731f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
732f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public static class Arguments {
733f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** whether to run in debug mode */
734f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public boolean debug = false;
735f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
736f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** whether to emit high-level verbose human-oriented output */
737f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public boolean verbose = false;
738f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
739f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** whether to emit verbose human-oriented output in the dump file */
740f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public boolean verboseDump = false;
741f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
742f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** whether we are constructing a core library */
743f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public boolean coreLibrary = false;
744f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
74599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        /** {@code null-ok;} particular method to dump */
746f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public String methodToDump = null;
747f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
748f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** max width for columnar output */
749f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public int dumpWidth = 0;
750f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
75199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        /** {@code null-ok;} output file name for binary file */
752f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public String outName = null;
753f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
75499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        /** {@code null-ok;} output file name for human-oriented dump */
755f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public String humanOutName = null;
756f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
757f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** whether strict file-name-vs-class-name checking should be done */
758f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public boolean strictNameCheck = true;
759f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
760f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
76199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * whether it is okay for there to be no {@code .class} files
762f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * to process
763f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
764f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public boolean emptyOk = false;
765f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
766f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
76799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * whether the binary output is to be a {@code .jar} file
76899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * instead of a plain {@code .dex}
769f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
770f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public boolean jarOutput = false;
771f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
772f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
77399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * when writing a {@code .jar} file, whether to still
77499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * keep the {@code .class} files
775f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
776f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public boolean keepClassesInJar = false;
777f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
778f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** how much source position info to preserve */
779f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public int positionInfo = PositionList.LINES;
780f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
781f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** whether to keep local variable information */
782f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public boolean localInfo = true;
783f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
78499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        /** {@code non-null after {@link #parse};} file name arguments */
785f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public String[] fileNames;
786f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
787f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** whether to do SSA/register optimization */
788f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public boolean optimize = true;
789f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
790f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** Filename containg list of methods to optimize */
791f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public String optimizeListFile = null;
792f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
793f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** Filename containing list of methods to NOT optimize */
794f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public String dontOptimizeListFile = null;
795f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
796f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** Whether to print statistics to stdout at end of compile cycle */
797f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public boolean statistics;
798f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
799f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** Options for dex.cf.* */
800f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public CfOptions cfOptions;
801f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
8021e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll        private static class ArgumentsParser {
8031e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll
8041e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            /** The arguments to process. */
8051e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            private final String[] arguments;
8061e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            /** The index of the next argument to process. */
8071e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            private int index;
8081e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            /** The current argument being processed after a {@link #getNext()} call. */
8091e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            private String current;
8101e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            /** The last value of an argument processed by {@link #isArg(String)}. */
8111e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            private String lastValue;
8121e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll
8131e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            public ArgumentsParser(String[] arguments) {
8141e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                this.arguments = arguments;
8151e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                index = 0;
8161e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            }
8171e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll
8181e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            public String getCurrent() {
8191e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                return current;
8201e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            }
8211e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll
8221e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            public String getLastValue() {
8231e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                return lastValue;
8241e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            }
8251e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll
8261e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            /**
8271e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll             * Moves on to the next argument.
8281e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll             * Returns false when we ran out of arguments that start with --.
8291e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll             */
8301e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            public boolean getNext() {
8311e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                if (index >= arguments.length) {
8321e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                    return false;
8331e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                }
8341e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                current = arguments[index];
8351e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                if (current.equals("--") || !current.startsWith("--")) {
8361e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                    return false;
8371e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                }
8381e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                index++;
8391e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                return true;
8401e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            }
8411e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll
8421e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            /**
8431e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll             * Similar to {@link #getNext()}, this moves on the to next argument.
8441e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll             * It does not check however whether the argument starts with --
8451e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll             * and thus can be used to retrieve values.
8461e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll             */
8471e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            private boolean getNextValue() {
8481e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                if (index >= arguments.length) {
8491e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                    return false;
8501e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                }
8511e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                current = arguments[index];
8521e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                index++;
8531e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                return true;
8541e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            }
8551e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll
8561e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            /**
8571e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll             * Returns all the arguments that have not been processed yet.
8581e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll             */
8591e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            public String[] getRemaining() {
8601e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                int n = arguments.length - index;
8611e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                String[] remaining = new String[n];
8621e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                if (n > 0) {
8631e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                    System.arraycopy(arguments, index, remaining, 0, n);
8641e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                }
8651e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                return remaining;
8661e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            }
8671e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll
8681e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            /**
8691e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll             * Checks the current argument against the given prefix.
8701e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll             * If prefix is in the form '--name=', an extra value is expected.
8711e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll             * The argument can then be in the form '--name=value' or as a 2-argument
8721e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll             * form '--name value'.
8731e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll             */
8741e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            public boolean isArg(String prefix) {
8751e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                int n = prefix.length();
8761e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                if (n > 0 && prefix.charAt(n-1) == '=') {
8771e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                    // Argument accepts a value. Capture it.
8781e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                    if (current.startsWith(prefix)) {
8791e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                        // Argument is in the form --name=value, split the value out
8801e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                        lastValue = current.substring(n);
8811e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                        return true;
8821e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                    } else {
8831e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                        // Check whether we have "--name value" as 2 arguments
8841e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                        prefix = prefix.substring(0, n-1);
8851e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                        if (current.equals(prefix)) {
8861e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                            if (getNextValue()) {
8871e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                                lastValue = current;
8881e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                                return true;
8891e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                            } else {
8901e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                                System.err.println("Missing value after parameter " + prefix);
8911e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                                throw new UsageException();
8921e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                            }
8931e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                        }
8941e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                        return false;
8951e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                    }
8961e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                } else {
8971e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                    // Argument does not accept a value.
8981e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                    return current.equals(prefix);
8991e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                }
9001e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            }
9011e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll        }
9021e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll
903f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
904f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Parses the given command-line arguments.
905f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         *
90699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * @param args {@code non-null;} the arguments
907f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
908f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public void parse(String[] args) {
9091e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            ArgumentsParser parser = new ArgumentsParser(args);
910f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
9111e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            while(parser.getNext()) {
9121e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                if (parser.isArg("--debug")) {
913f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    debug = true;
9141e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                } else if (parser.isArg("--verbose")) {
915f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    verbose = true;
9161e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                } else if (parser.isArg("--verbose-dump")) {
917f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    verboseDump = true;
9181e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                } else if (parser.isArg("--no-files")) {
919f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    emptyOk = true;
9201e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                } else if (parser.isArg("--no-optimize")) {
921f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    optimize = false;
9221e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                } else if (parser.isArg("--no-strict")) {
923f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    strictNameCheck = false;
9241e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                } else if (parser.isArg("--core-library")) {
925f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    coreLibrary = true;
9261e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                } else if (parser.isArg("--statistics")) {
927f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    statistics = true;
9281e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                } else if (parser.isArg("--optimize-list=")) {
929f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    if (dontOptimizeListFile != null) {
930f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        System.err.println("--optimize-list and "
931f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                + "--no-optimize-list are incompatible.");
932f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        throw new UsageException();
933f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
934f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    optimize = true;
9351e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                    optimizeListFile = parser.getLastValue();
9361e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                } else if (parser.isArg("--no-optimize-list=")) {
937f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    if (dontOptimizeListFile != null) {
938f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        System.err.println("--optimize-list and "
939f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                + "--no-optimize-list are incompatible.");
940f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        throw new UsageException();
941f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
942f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    optimize = true;
9431e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                    dontOptimizeListFile = parser.getLastValue();
9441e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                } else if (parser.isArg("--keep-classes")) {
945f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    keepClassesInJar = true;
9461e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                } else if (parser.isArg("--output=")) {
9471e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                    outName = parser.getLastValue();
948f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    if (outName.endsWith(".zip") ||
949f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            outName.endsWith(".jar") ||
950f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            outName.endsWith(".apk")) {
951f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        jarOutput = true;
952f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    } else if (outName.endsWith(".dex") ||
953f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                               outName.equals("-")) {
954f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        jarOutput = false;
955f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    } else {
956f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        System.err.println("unknown output extension: " +
957f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                           outName);
958f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        throw new UsageException();
959f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
9601e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                } else if (parser.isArg("--dump-to=")) {
9611e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                    humanOutName = parser.getLastValue();
9621e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                } else if (parser.isArg("--dump-width=")) {
9631e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                    dumpWidth = Integer.parseInt(parser.getLastValue());
9641e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                } else if (parser.isArg("--dump-method=")) {
9651e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                    methodToDump = parser.getLastValue();
966f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    jarOutput = false;
9671e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                } else if (parser.isArg("--positions=")) {
9681e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                    String pstr = parser.getLastValue().intern();
969f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    if (pstr == "none") {
970f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        positionInfo = PositionList.NONE;
971f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    } else if (pstr == "important") {
972f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        positionInfo = PositionList.IMPORTANT;
973f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    } else if (pstr == "lines") {
974f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        positionInfo = PositionList.LINES;
975f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    } else {
976f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        System.err.println("unknown positions option: " +
977f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                           pstr);
978f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        throw new UsageException();
979f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
9801e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                } else if (parser.isArg("--no-locals")) {
981f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    localInfo = false;
982f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                } else {
9831e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll                    System.err.println("unknown option: " + parser.getCurrent());
984f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    throw new UsageException();
985f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
986f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
987f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
9881e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            fileNames = parser.getRemaining();
9891e4c4bebc1feb4b68155e9c2e7e6f2c056ef8e3bRaphael Moll            if (fileNames.length == 0) {
990f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (!emptyOk) {
991f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    System.err.println("no input files specified");
992f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    throw new UsageException();
993f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
994f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else if (emptyOk) {
995f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                System.out.println("ignoring input files");
996f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
997f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
998f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if ((humanOutName == null) && (methodToDump != null)) {
999f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                humanOutName = "-";
1000f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1001f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1002f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            makeCfOptions();
1003f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1004f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1005f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
1006f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Copies relevent arguments over into a CfOptions instance.
1007f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
1008f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        private void makeCfOptions() {
1009f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            cfOptions = new CfOptions();
1010f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1011f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            cfOptions.positionInfo = positionInfo;
1012f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            cfOptions.localInfo = localInfo;
1013f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            cfOptions.strictNameCheck = strictNameCheck;
1014f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            cfOptions.optimize = optimize;
1015f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            cfOptions.optimizeListFile = optimizeListFile;
1016f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            cfOptions.dontOptimizeListFile = dontOptimizeListFile;
1017f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            cfOptions.statistics = statistics;
1018f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            cfOptions.warn = DxConsole.err;
1019f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1020f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1021f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
1022