1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.bcel.util;
20
21 import java.io.File;
22 import java.io.FileNotFoundException;
23 import java.io.IOException;
24 import java.io.PrintWriter;
25 import java.io.UnsupportedEncodingException;
26 import java.nio.charset.Charset;
27 import java.nio.charset.StandardCharsets;
28 import java.util.HashSet;
29 import java.util.Set;
30
31 import org.apache.bcel.Const;
32 import org.apache.bcel.Constants;
33 import org.apache.bcel.classfile.Attribute;
34 import org.apache.bcel.classfile.ClassParser;
35 import org.apache.bcel.classfile.ConstantPool;
36 import org.apache.bcel.classfile.JavaClass;
37 import org.apache.bcel.classfile.Method;
38 import org.apache.bcel.classfile.Utility;
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56 public class Class2HTML implements Constants {
57
58 private static String classPackage;
59 private static String className;
60 private static ConstantPool constantPool;
61 private static final Set<String> basicTypes = new HashSet<>();
62 static {
63 basicTypes.add("int");
64 basicTypes.add("short");
65 basicTypes.add("boolean");
66 basicTypes.add("void");
67 basicTypes.add("char");
68 basicTypes.add("byte");
69 basicTypes.add("long");
70 basicTypes.add("double");
71 basicTypes.add("float");
72 }
73
74
75
76
77
78
79
80
81
82
83
84 private static void checkFileNameSafe(final String name) throws IOException {
85 for (int i = 0; i < name.length(); i++) {
86 final char c = name.charAt(i);
87 if (c < ' ' || "\\/:*?\"<>|".indexOf(c) >= 0) {
88 throw new IOException("Refusing to write HTML for a class whose name contains the unsafe character (0x"
89 + Integer.toHexString(c) + "): " + name);
90 }
91 }
92 if (name.contains("..")) {
93 throw new IOException("Refusing to write HTML for a class whose name contains \"..\": " + name);
94 }
95 }
96
97
98
99
100
101
102
103 public static void main(final String[] argv) throws IOException {
104 final String[] fileName = new String[argv.length];
105 int files = 0;
106 ClassParser parser = null;
107 JavaClass javaClass = null;
108 String zipFile = null;
109 final char sep = File.separatorChar;
110 String dir = "." + sep;
111
112
113
114 for (int i = 0; i < argv.length; i++) {
115 if (argv[i].charAt(0) == '-') {
116 if (argv[i].equals("-d")) {
117 dir = argv[++i];
118 if (!dir.endsWith("" + sep)) {
119 dir += sep;
120 }
121 final File store = new File(dir);
122 if (!store.isDirectory()) {
123 final boolean created = store.mkdirs();
124 if (!created && !store.isDirectory()) {
125 System.out.println("Tried to create the directory " + dir + " but failed");
126 }
127 }
128 } else if (argv[i].equals("-zip")) {
129 zipFile = argv[++i];
130 } else {
131 System.out.println("Unknown option " + argv[i]);
132 }
133 } else {
134 fileName[files++] = argv[i];
135 }
136 }
137 if (files == 0) {
138 System.err.println("Class2HTML: No input files specified.");
139 } else {
140 for (int i = 0; i < files; i++) {
141 System.out.print("Processing " + fileName[i] + "...");
142 if (zipFile == null) {
143 parser = new ClassParser(fileName[i]);
144 } else {
145 parser = new ClassParser(zipFile, fileName[i]);
146 }
147 javaClass = parser.parse();
148 new Class2HTML(javaClass, dir);
149 System.out.println("Done.");
150 }
151 }
152 }
153
154
155
156
157 static String referenceClass(final int index) {
158 String str = constantPool.getConstantString(index, Const.CONSTANT_Class);
159 str = Utility.compactClassName(str);
160 str = Utility.compactClassName(str, classPackage + ".", true);
161 return "<A HREF=\"" + className + "_cp.html#cp" + index + "\" TARGET=ConstantPool>" + toHTML(str) + "</A>";
162 }
163
164 static String referenceType(final String type) {
165 String shortType = Utility.compactClassName(type);
166 shortType = Utility.compactClassName(shortType, classPackage + ".", true);
167 final int index = type.indexOf('[');
168 String baseType = type;
169 if (index > -1) {
170 baseType = type.substring(0, index);
171 }
172
173 if (basicTypes.contains(baseType)) {
174 return "<FONT COLOR=\"#00FF00\">" + type + "</FONT>";
175 }
176 return "<A HREF=\"" + toHTMLRef(baseType) + ".html\" TARGET=_top>" + toHTML(shortType) + "</A>";
177 }
178
179 static String toHTML(final String str) {
180 final StringBuilder buf = new StringBuilder();
181 for (int i = 0; i < str.length(); i++) {
182 final char ch;
183 switch (ch = str.charAt(i)) {
184 case '&':
185 buf.append("&");
186 break;
187 case '<':
188 buf.append("<");
189 break;
190 case '>':
191 buf.append(">");
192 break;
193 case '"':
194 buf.append(""");
195 break;
196 case '\'':
197 buf.append("'");
198 break;
199 case '\n':
200 buf.append("\\n");
201 break;
202 case '\r':
203 buf.append("\\r");
204 break;
205 default:
206 buf.append(ch);
207 }
208 }
209 return buf.toString();
210 }
211
212
213
214
215
216
217 static String toHTMLRef(final String str) {
218 return toHTML(str.replace(':', '_'));
219 }
220
221 private final JavaClass javaClass;
222
223 private final String dir;
224
225
226
227
228
229
230
231
232 public Class2HTML(final JavaClass javaClass, final String dir) throws IOException {
233 this(javaClass, dir, StandardCharsets.UTF_8);
234 }
235
236 private Class2HTML(final JavaClass javaClass, final String dir, final Charset charset) throws IOException {
237 final Method[] methods = javaClass.getMethods();
238 this.javaClass = javaClass;
239 this.dir = dir;
240 className = javaClass.getClassName();
241 checkFileNameSafe(className);
242 constantPool = javaClass.getConstantPool();
243
244 final int index = className.lastIndexOf('.');
245 if (index > -1) {
246 classPackage = className.substring(0, index);
247 } else {
248 classPackage = "";
249 }
250 final ConstantHTML constantHtml = new ConstantHTML(dir, className, classPackage, methods, constantPool, charset);
251
252
253
254 try (AttributeHTML attributeHtml = new AttributeHTML(dir, className, constantPool, constantHtml, charset)) {
255 new MethodHTML(dir, className, methods, javaClass.getFields(), constantHtml, attributeHtml, charset);
256
257 writeMainHTML(attributeHtml, charset);
258 new CodeHTML(dir, className, methods, constantPool, constantHtml, charset);
259 }
260 }
261
262 private void writeMainHTML(final AttributeHTML attributeHtml, final Charset charset) throws FileNotFoundException, UnsupportedEncodingException {
263 try (PrintWriter file = new PrintWriter(dir + className + ".html", charset.name())) {
264
265 file.println("<HTML>\n"
266 + "<HEAD><TITLE>Documentation for " + toHTML(className) + "</TITLE></HEAD>\n"
267 + "<FRAMESET BORDER=1 cols=\"30%,*\">\n"
268 + "<FRAMESET BORDER=1 rows=\"80%,*\">\n"
269 + "<FRAME NAME=\"ConstantPool\" SRC=\"" + className + "_cp.html" + "\"\n"
270 + "MARGINWIDTH=\"0\" "
271 + "MARGINHEIGHT=\"0\" FRAMEBORDER=\"1\" SCROLLING=\"AUTO\">\n"
272 + "<FRAME NAME=\"Attributes\" SRC=\"" + className + "_attributes.html\"\n"
273 + " MARGINWIDTH=\"0\" MARGINHEIGHT=\"0\" FRAMEBORDER=\"1\" SCROLLING=\"AUTO\">\n"
274 + "</FRAMESET>\n"
275 + "<FRAMESET BORDER=1 rows=\"80%,*\">\n"
276 + "<FRAME NAME=\"Code\" SRC=\"" + className + "_code.html\"\n"
277 + " MARGINWIDTH=0 "
278 + "MARGINHEIGHT=0 FRAMEBORDER=1 SCROLLING=\"AUTO\">\n"
279 + "<FRAME NAME=\"Methods\" SRC=\"" + className + "_methods.html\"\n"
280 + " MARGINWIDTH=0 "
281 + "MARGINHEIGHT=0 FRAMEBORDER=1 SCROLLING=\"AUTO\">\n"
282 + "</FRAMESET></FRAMESET></HTML>");
283
284 }
285 final Attribute[] attributes = javaClass.getAttributes();
286 for (int i = 0; i < attributes.length; i++) {
287 attributeHtml.writeAttribute(attributes[i], "class" + i);
288 }
289 }
290 }