aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/apache/bcel/util/Class2HTML.java
blob: a0e93497af72e043360e3444511f8fdfdeff9192 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */
package org.apache.bcel.util;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashSet;
import java.util.Set;

import org.apache.bcel.Const;
import org.apache.bcel.Constants;
import org.apache.bcel.classfile.Attribute;
import org.apache.bcel.classfile.ClassParser;
import org.apache.bcel.classfile.ConstantPool;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.Method;
import org.apache.bcel.classfile.Utility;

/**
 * Read class file(s) and convert them into HTML files.
 *
 * Given a JavaClass object "class" that is in package "package" five files
 * will be created in the specified directory.
 *
 * <OL>
 * <LI> "package"."class".html as the main file which defines the frames for
 * the following subfiles.
 * <LI>  "package"."class"_attributes.html contains all (known) attributes found in the file
 * <LI>  "package"."class"_cp.html contains the constant pool
 * <LI>  "package"."class"_code.html contains the byte code
 * <LI>  "package"."class"_methods.html contains references to all methods and fields of the class
 * </OL>
 *
 * All subfiles reference each other appropriately, e.g. clicking on a
 * method in the Method's frame will jump to the appropriate method in
 * the Code frame.
 *
 * @version $Id$
 */
public class Class2HTML implements Constants {

    private final JavaClass java_class; // current class object
    private final String dir;
    private static String class_package; // name of package, unclean to make it static, but ...
    private static String class_name; // name of current class, dito
    private static ConstantPool constant_pool;
    private static final Set<String> basic_types = new HashSet<>();

    static {
        basic_types.add("int");
        basic_types.add("short");
        basic_types.add("boolean");
        basic_types.add("void");
        basic_types.add("char");
        basic_types.add("byte");
        basic_types.add("long");
        basic_types.add("double");
        basic_types.add("float");
    }

    /**
     * Write contents of the given JavaClass into HTML files.
     *
     * @param java_class The class to write
     * @param dir The directory to put the files in
     */
    public Class2HTML(final JavaClass java_class, final String dir) throws IOException {
        final Method[] methods = java_class.getMethods();
        this.java_class = java_class;
        this.dir = dir;
        class_name = java_class.getClassName(); // Remember full name
        constant_pool = java_class.getConstantPool();
        // Get package name by tacking off everything after the last `.'
        final int index = class_name.lastIndexOf('.');
        if (index > -1) {
            class_package = class_name.substring(0, index);
        } else {
            class_package = ""; // default package
        }
        final ConstantHTML constant_html = new ConstantHTML(dir, class_name, class_package, methods,
                constant_pool);
        /* Attributes can't be written in one step, so we just open a file
         * which will be written consequently.
         */
        final AttributeHTML attribute_html = new AttributeHTML(dir, class_name, constant_pool,
                constant_html);
        new MethodHTML(dir, class_name, methods, java_class.getFields(),
                constant_html, attribute_html);
        // Write main file (with frames, yuk)
        writeMainHTML(attribute_html);
        new CodeHTML(dir, class_name, methods, constant_pool, constant_html);
        attribute_html.close();
    }


    public static void main( final String[] argv ) throws IOException {
        final String[] file_name = new String[argv.length];
        int files = 0;
        ClassParser parser = null;
        JavaClass java_class = null;
        String zip_file = null;
        final char sep = File.separatorChar;
        String dir = "." + sep; // Where to store HTML files
        /* Parse command line arguments.
         */
        for (int i = 0; i < argv.length; i++) {
            if (argv[i].charAt(0) == '-') { // command line switch
                if (argv[i].equals("-d")) { // Specify target directory, default '.'
                    dir = argv[++i];
                    if (!dir.endsWith("" + sep)) {
                        dir = dir + sep;
                    }
                    final File store = new File(dir);
                    if (!store.isDirectory()) {
                        final boolean created = store.mkdirs(); // Create target directory if necessary
                        if (!created) {
                            if (!store.isDirectory()) {
                                System.out.println("Tried to create the directory " + dir + " but failed");
                            }
                        }
                    }
                } else if (argv[i].equals("-zip")) {
                    zip_file = argv[++i];
                } else {
                    System.out.println("Unknown option " + argv[i]);
                }
            } else {
                file_name[files++] = argv[i];
            }
        }
        if (files == 0) {
            System.err.println("Class2HTML: No input files specified.");
        } else { // Loop through files ...
            for (int i = 0; i < files; i++) {
                System.out.print("Processing " + file_name[i] + "...");
                if (zip_file == null) {
                    parser = new ClassParser(file_name[i]); // Create parser object from file
                } else {
                    parser = new ClassParser(zip_file, file_name[i]); // Create parser object from zip file
                }
                java_class = parser.parse();
                new Class2HTML(java_class, dir);
                System.out.println("Done.");
            }
        }
    }


    /**
     * Utility method that converts a class reference in the constant pool,
     * i.e., an index to a string.
     */
    static String referenceClass( final int index ) {
        String str = constant_pool.getConstantString(index, Const.CONSTANT_Class);
        str = Utility.compactClassName(str);
        str = Utility.compactClassName(str, class_package + ".", true);
        return "<A HREF=\"" + class_name + "_cp.html#cp" + index + "\" TARGET=ConstantPool>" + str
                + "</A>";
    }


    static String referenceType( final String type ) {
        String short_type = Utility.compactClassName(type);
        short_type = Utility.compactClassName(short_type, class_package + ".", true);
        final int index = type.indexOf('['); // Type is an array?
        String base_type = type;
        if (index > -1) {
            base_type = type.substring(0, index); // Tack of the `['
        }
        // test for basic type
        if (basic_types.contains(base_type)) {
            return "<FONT COLOR=\"#00FF00\">" + type + "</FONT>";
        }
        return "<A HREF=\"" + base_type + ".html\" TARGET=_top>" + short_type + "</A>";
    }


    static String toHTML( final String str ) {
        final StringBuilder buf = new StringBuilder();
        for (int i = 0; i < str.length(); i++) {
            char ch;
            switch (ch = str.charAt(i)) {
                case '<':
                    buf.append("&lt;");
                    break;
                case '>':
                    buf.append("&gt;");
                    break;
                case '\n':
                    buf.append("\\n");
                    break;
                case '\r':
                    buf.append("\\r");
                    break;
                default:
                    buf.append(ch);
            }
        }
        return buf.toString();
    }


    private void writeMainHTML( final AttributeHTML attribute_html ) throws IOException {
        try (PrintWriter file = new PrintWriter(new FileOutputStream(dir + class_name + ".html"))) {
            file.println("<HTML>\n" + "<HEAD><TITLE>Documentation for " + class_name + "</TITLE>" + "</HEAD>\n"
                    + "<FRAMESET BORDER=1 cols=\"30%,*\">\n" + "<FRAMESET BORDER=1 rows=\"80%,*\">\n"
                    + "<FRAME NAME=\"ConstantPool\" SRC=\"" + class_name + "_cp.html" + "\"\n MARGINWIDTH=\"0\" "
                    + "MARGINHEIGHT=\"0\" FRAMEBORDER=\"1\" SCROLLING=\"AUTO\">\n" + "<FRAME NAME=\"Attributes\" SRC=\""
                    + class_name + "_attributes.html" + "\"\n MARGINWIDTH=\"0\" "
                    + "MARGINHEIGHT=\"0\" FRAMEBORDER=\"1\" SCROLLING=\"AUTO\">\n" + "</FRAMESET>\n"
                    + "<FRAMESET BORDER=1 rows=\"80%,*\">\n" + "<FRAME NAME=\"Code\" SRC=\"" + class_name
                    + "_code.html\"\n MARGINWIDTH=0 " + "MARGINHEIGHT=0 FRAMEBORDER=1 SCROLLING=\"AUTO\">\n"
                    + "<FRAME NAME=\"Methods\" SRC=\"" + class_name + "_methods.html\"\n MARGINWIDTH=0 "
                    + "MARGINHEIGHT=0 FRAMEBORDER=1 SCROLLING=\"AUTO\">\n" + "</FRAMESET></FRAMESET></HTML>");
        }
        final Attribute[] attributes = java_class.getAttributes();
        for (int i = 0; i < attributes.length; i++) {
            attribute_html.writeAttribute(attributes[i], "class" + i);
        }
    }
}