112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden/* 212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden * Copyright (C) 2009 The Android Open Source Project 312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden * 412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden * Licensed under the Apache License, Version 2.0 (the "License"); 512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden * you may not use this file except in compliance with the License. 612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden * You may obtain a copy of the License at 712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden * 812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden * http://www.apache.org/licenses/LICENSE-2.0 912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden * 1012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden * Unless required by applicable law or agreed to in writing, software 1112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden * distributed under the License is distributed on an "AS IS" BASIS, 1212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden * See the License for the specific language governing permissions and 1412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden * limitations under the License. 1512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden */ 1612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden 1712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFaddenpackage com.android.dexdeps; 1812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden 1906d020698f7182ae17b933fa688ab9302a8674e2Dan Bornsteinimport java.io.PrintStream; 2006d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein 2112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden/** 2212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden * Generate fancy output. 2312d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden */ 2412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFaddenpublic class Output { 25837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden private static final String IN0 = ""; 26837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden private static final String IN1 = " "; 27837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden private static final String IN2 = " "; 28837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden private static final String IN3 = " "; 29837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden private static final String IN4 = " "; 30837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden 3106d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein private static final PrintStream out = System.out; 3206d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein 3306d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein private static void generateHeader0(String fileName, String format) { 3406d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein if (format.equals("brief")) { 3506d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein if (fileName != null) { 3606d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein out.println("File: " + fileName); 3706d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein } 3806d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein } else if (format.equals("xml")) { 3906d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein if (fileName != null) { 4006d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein out.println(IN0 + "<external file=\"" + fileName + "\">"); 4106d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein } else { 4206d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein out.println(IN0 + "<external>"); 4306d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein } 4406d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein } else { 4506d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein /* should've been trapped in arg handler */ 4606d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein throw new RuntimeException("unknown output format"); 4706d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein } 4806d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein } 4906d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein 5006d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein public static void generateFirstHeader(String fileName, String format) { 5106d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein generateHeader0(fileName, format); 5206d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein } 5306d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein 5406d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein public static void generateHeader(String fileName, String format) { 5506d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein out.println(); 5606d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein generateHeader0(fileName, format); 5706d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein } 5806d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein 5906d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein public static void generateFooter(String format) { 6006d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein if (format.equals("brief")) { 6106d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein // Nothing to do. 6206d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein } else if (format.equals("xml")) { 6306d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein out.println("</external>"); 6406d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein } else { 6506d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein /* should've been trapped in arg handler */ 6606d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein throw new RuntimeException("unknown output format"); 6706d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein } 6806d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein } 6906d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein 7006d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein public static void generate(DexData dexData, String format, 7106d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein boolean justClasses) { 7212d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden if (format.equals("brief")) { 7306d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein printBrief(dexData, justClasses); 7412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden } else if (format.equals("xml")) { 7506d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein printXml(dexData, justClasses); 7612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden } else { 7712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden /* should've been trapped in arg handler */ 7812d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden throw new RuntimeException("unknown output format"); 7912d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden } 8012d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden } 8112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden 82753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden /** 83753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden * Prints the data in a simple human-readable format. 84753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden */ 8506d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein static void printBrief(DexData dexData, boolean justClasses) { 86837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden ClassRef[] externClassRefs = dexData.getExternalReferences(); 87753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden 8806d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein printClassRefs(externClassRefs, justClasses); 8906d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein 9006d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein if (!justClasses) { 9106d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein printFieldRefs(externClassRefs); 9206d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein printMethodRefs(externClassRefs); 9306d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein } 94837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden } 95837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden 96837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden /** 97837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden * Prints the list of classes in a simple human-readable format. 98837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden */ 9906d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein static void printClassRefs(ClassRef[] classes, boolean justClasses) { 10006d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein if (!justClasses) { 10106d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein out.println("Classes:"); 10206d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein } 10306d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein 104837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden for (int i = 0; i < classes.length; i++) { 105837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden ClassRef ref = classes[i]; 106837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden 10706d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein out.println(descriptorToDot(ref.getName())); 108837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden } 109753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden } 110753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden 111753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden /** 112753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden * Prints the list of fields in a simple human-readable format. 113753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden */ 114837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden static void printFieldRefs(ClassRef[] classes) { 11506d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein out.println("\nFields:"); 116837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden for (int i = 0; i < classes.length; i++) { 117837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden FieldRef[] fields = classes[i].getFieldArray(); 118837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden 119837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden for (int j = 0; j < fields.length; j++) { 120837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden FieldRef ref = fields[j]; 12112d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden 12206d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein out.println(descriptorToDot(ref.getDeclClassName()) + 123837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden "." + ref.getName() + " : " + ref.getTypeName()); 124837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden } 12512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden } 12612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden } 12712d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden 128753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden /** 129753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden * Prints the list of methods in a simple human-readable format. 130753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden */ 131837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden static void printMethodRefs(ClassRef[] classes) { 13206d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein out.println("\nMethods:"); 133837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden for (int i = 0; i < classes.length; i++) { 134837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden MethodRef[] methods = classes[i].getMethodArray(); 13512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden 136837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden for (int j = 0; j < methods.length; j++) { 137837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden MethodRef ref = methods[j]; 138837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden 13906d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein out.println(descriptorToDot(ref.getDeclClassName()) + 140837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden "." + ref.getName() + " : " + ref.getDescriptor()); 141837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden } 142753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden } 143753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden } 144753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden 145753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden /** 146753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden * Prints the output in XML format. 147753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden * 148753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden * We shouldn't need to XML-escape the field/method info. 149753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden */ 15006d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein static void printXml(DexData dexData, boolean justClasses) { 151837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden ClassRef[] externClassRefs = dexData.getExternalReferences(); 152753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden 153837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden /* 154837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden * Iterate through externClassRefs. For each class, dump all of 155837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden * the matching fields and methods. 156837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden */ 157837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden String prevPackage = null; 158837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden for (int i = 0; i < externClassRefs.length; i++) { 159837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden ClassRef cref = externClassRefs[i]; 160837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden String declClassName = cref.getName(); 161837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden String className = classNameOnly(declClassName); 162837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden String packageName = packageNameOnly(declClassName); 163837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden 164837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden /* 165837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden * If we're in a different package, emit the appropriate tags. 166837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden */ 167837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden if (!packageName.equals(prevPackage)) { 168837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden if (prevPackage != null) { 16906d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein out.println(IN1 + "</package>"); 170837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden } 171837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden 17206d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein out.println(IN1 + 173837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden "<package name=\"" + packageName + "\">"); 174837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden 175837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden prevPackage = packageName; 176753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden } 177753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden 17806d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein out.println(IN2 + "<class name=\"" + className + "\">"); 17906d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein if (!justClasses) { 18006d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein printXmlFields(cref); 18106d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein printXmlMethods(cref); 18206d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein } 18306d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein out.println(IN2 + "</class>"); 184837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden } 185837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden 186837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden if (prevPackage != null) 18706d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein out.println(IN1 + "</package>"); 188837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden } 189837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden 190837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden /** 191837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden * Prints the externally-visible fields in XML format. 192837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden */ 193837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden private static void printXmlFields(ClassRef cref) { 194837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden FieldRef[] fields = cref.getFieldArray(); 195837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden for (int i = 0; i < fields.length; i++) { 196837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden FieldRef fref = fields[i]; 197837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden 19806d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein out.println(IN3 + "<field name=\"" + fref.getName() + 199753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden "\" type=\"" + descriptorToDot(fref.getTypeName()) + "\"/>"); 200753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden } 201837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden } 202753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden 203837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden /** 204837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden * Prints the externally-visible methods in XML format. 205837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden */ 206837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden private static void printXmlMethods(ClassRef cref) { 207837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden MethodRef[] methods = cref.getMethodArray(); 208837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden for (int i = 0; i < methods.length; i++) { 209837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden MethodRef mref = methods[i]; 210753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden String declClassName = mref.getDeclClassName(); 211753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden boolean constructor; 212753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden 213753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden constructor = mref.getName().equals("<init>"); 214753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden if (constructor) { 215837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden // use class name instead of method name 21606d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein out.println(IN3 + "<constructor name=\"" + 217837070dd1e39c87370239643f0df2e2ab9d41fc9Andy McFadden classNameOnly(declClassName) + "\">"); 218753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden } else { 21906d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein out.println(IN3 + "<method name=\"" + mref.getName() + 220753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden "\" return=\"" + descriptorToDot(mref.getReturnTypeName()) + 221753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden "\">"); 222753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden } 223753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden String[] args = mref.getArgumentTypeNames(); 224753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden for (int j = 0; j < args.length; j++) { 22506d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein out.println(IN4 + "<parameter type=\"" + 226753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden descriptorToDot(args[j]) + "\"/>"); 227753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden } 228753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden if (constructor) { 22906d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein out.println(IN3 + "</constructor>"); 230753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden } else { 23106d020698f7182ae17b933fa688ab9302a8674e2Dan Bornstein out.println(IN3 + "</method>"); 232753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden } 233753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden } 234753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden } 235753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden 236753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden 237753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden /* 238753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden * ======================================================================= 239753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden * Utility functions 240753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden * ======================================================================= 241753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden */ 242753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden 243753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden /** 244753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden * Converts a single-character primitive type into its human-readable 245753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden * equivalent. 246753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden */ 247753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden static String primitiveTypeLabel(char typeChar) { 248753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden /* primitive type; substitute human-readable name in */ 249753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden switch (typeChar) { 250753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden case 'B': return "byte"; 251753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden case 'C': return "char"; 252753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden case 'D': return "double"; 253753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden case 'F': return "float"; 254753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden case 'I': return "int"; 255753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden case 'J': return "long"; 256753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden case 'S': return "short"; 257753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden case 'V': return "void"; 258753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden case 'Z': return "boolean"; 259753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden default: 260753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden /* huh? */ 261753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden System.err.println("Unexpected class char " + typeChar); 262753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden assert false; 263753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden return "UNKNOWN"; 264753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden } 265753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden } 266753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden 267753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden /** 268753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden * Converts a type descriptor to human-readable "dotted" form. For 269753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden * example, "Ljava/lang/String;" becomes "java.lang.String", and 270753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden * "[I" becomes "int[]. 271753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden */ 272753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden static String descriptorToDot(String descr) { 273753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden int targetLen = descr.length(); 274753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden int offset = 0; 275753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden int arrayDepth = 0; 276753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden 277753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden /* strip leading [s; will be added to end */ 278753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden while (targetLen > 1 && descr.charAt(offset) == '[') { 279753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden offset++; 280753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden targetLen--; 281753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden } 282753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden arrayDepth = offset; 283753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden 284753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden if (targetLen == 1) { 285753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden descr = primitiveTypeLabel(descr.charAt(offset)); 286753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden offset = 0; 287753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden targetLen = descr.length(); 288753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden } else { 289753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden /* account for leading 'L' and trailing ';' */ 290753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden if (targetLen >= 2 && descr.charAt(offset) == 'L' && 291753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden descr.charAt(offset+targetLen-1) == ';') 292753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden { 293753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden targetLen -= 2; /* two fewer chars to copy */ 294753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden offset++; /* skip the 'L' */ 295753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden } 296753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden } 297753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden 298753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden char[] buf = new char[targetLen + arrayDepth * 2]; 299753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden 300753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden /* copy class name over */ 301753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden int i; 302753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden for (i = 0; i < targetLen; i++) { 303753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden char ch = descr.charAt(offset + i); 304753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden buf[i] = (ch == '/') ? '.' : ch; 305753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden } 306753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden 307753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden /* add the appopriate number of brackets for arrays */ 308753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden while (arrayDepth-- > 0) { 309753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden buf[i++] = '['; 310753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden buf[i++] = ']'; 311753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden } 312753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden assert i == buf.length; 313753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden 314753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden return new String(buf); 315753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden } 316753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden 317753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden /** 318753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden * Extracts the class name from a type descriptor. 319753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden */ 320753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden static String classNameOnly(String typeName) { 321753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden String dotted = descriptorToDot(typeName); 322753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden 323753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden int start = dotted.lastIndexOf("."); 324753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden if (start < 0) { 325753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden return dotted; 326753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden } else { 327753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden return dotted.substring(start+1); 328753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden } 329753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden } 330753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden 331753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden /** 332753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden * Extracts the package name from a type descriptor, and returns it in 333753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden * dotted form. 334753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden */ 335753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden static String packageNameOnly(String typeName) { 336753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden String dotted = descriptorToDot(typeName); 337753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden 338753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden int end = dotted.lastIndexOf("."); 339753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden if (end < 0) { 340753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden /* lives in default package */ 341753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden return ""; 342753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden } else { 343753f32ab1db6de174a1de68210f9f30a1e327612Andy McFadden return dotted.substring(0, end); 34412d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden } 34512d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden } 34612d6d4c0ea192b6a924df0df1e3b14ce1ed5793bAndy McFadden} 347