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