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