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 |
| package com.jeantessier.classreader; |
34 |
| |
35 |
| import com.google.common.annotations.VisibleForTesting; |
36 |
| import com.jeantessier.text.Hex; |
37 |
| |
38 |
| import java.io.PrintWriter; |
39 |
| import java.util.Collection; |
40 |
| |
41 |
| public class XMLPrinter extends Printer { |
42 |
| public static final String DEFAULT_ENCODING = "utf-8"; |
43 |
| public static final String DEFAULT_DTD_PREFIX = "http://depfind.sourceforge.net/dtd"; |
44 |
| |
45 |
| private static final BitFormat format = new BitFormat(16); |
46 |
| |
47 |
| private boolean top = true; |
48 |
| |
49 |
7
| public XMLPrinter(PrintWriter out) {
|
50 |
7
| this(out, DEFAULT_ENCODING, DEFAULT_DTD_PREFIX);
|
51 |
| } |
52 |
| |
53 |
124
| public XMLPrinter(PrintWriter out, String encoding, String dtdPrefix) {
|
54 |
124
| super(out);
|
55 |
| |
56 |
124
| appendHeader(encoding, dtdPrefix);
|
57 |
| } |
58 |
| |
59 |
124
| private void appendHeader(String encoding, String dtdPrefix) {
|
60 |
124
| append("<?xml version=\"1.0\" encoding=\"").append(encoding).append("\" ?>").eol();
|
61 |
124
| eol();
|
62 |
124
| append("<!DOCTYPE classfiles SYSTEM \"").append(dtdPrefix).append("/classfile.dtd\">").eol();
|
63 |
124
| eol();
|
64 |
| } |
65 |
| |
66 |
3
| public void visitClassfiles(Collection<Classfile> classfiles) {
|
67 |
3
| indent().append("<classfiles>").eol();
|
68 |
3
| raiseIndent();
|
69 |
| |
70 |
3
| super.visitClassfiles(classfiles);
|
71 |
| |
72 |
3
| lowerIndent();
|
73 |
3
| indent().append("</classfiles>").eol();
|
74 |
| } |
75 |
| |
76 |
32
| public void visitClassfile(Classfile classfile) {
|
77 |
32
| indent().append("<classfile magic-number=\"0x").append(Integer.toHexString(classfile.getMagicNumber()).toUpperCase()).append("\" minor-version=\"").append(classfile.getMinorVersion()).append("\" major-version=\"").append(classfile.getMajorVersion()).append("\" access-flag=\"").append(format.format(classfile.getAccessFlag())).append("\">").eol();
|
78 |
32
| raiseIndent();
|
79 |
| |
80 |
32
| top = true;
|
81 |
32
| classfile.getConstantPool().accept(this);
|
82 |
32
| top = false;
|
83 |
| |
84 |
17
| if (classfile.isPublic()) indent().append("<public/>").eol();
|
85 |
1
| if (classfile.isFinal()) indent().append("<final/>").eol();
|
86 |
11
| if (classfile.isSuper()) indent().append("<super/>").eol();
|
87 |
7
| if (classfile.isInterface()) indent().append("<is-interface/>").eol();
|
88 |
7
| if (classfile.isAbstract()) indent().append("<abstract/>").eol();
|
89 |
1
| if (classfile.isSynthetic()) indent().append("<synthetic/>").eol();
|
90 |
1
| if (classfile.isAnnotation()) indent().append("<is-annotation/>").eol();
|
91 |
1
| if (classfile.isEnum()) indent().append("<enum/>").eol();
|
92 |
| |
93 |
32
| indent();
|
94 |
32
| append("<this-class>");
|
95 |
32
| classfile.getRawClass().accept(this);
|
96 |
32
| append("</this-class>").eol();
|
97 |
| |
98 |
32
| indent();
|
99 |
32
| append("<superclass>");
|
100 |
32
| if (classfile.getSuperclassIndex() != 0) {
|
101 |
16
| classfile.getRawSuperclass().accept(this);
|
102 |
| } |
103 |
32
| append("</superclass>").eol();
|
104 |
| |
105 |
32
| if (!classfile.getAllInterfaces().isEmpty()) {
|
106 |
18
| indent().append("<interfaces>").eol();
|
107 |
18
| raiseIndent();
|
108 |
18
| for (Class_info class_info : classfile.getAllInterfaces()) {
|
109 |
2
| indent();
|
110 |
2
| append("<interface>");
|
111 |
2
| class_info.accept(this);
|
112 |
2
| append("</interface>").eol();
|
113 |
| } |
114 |
18
| lowerIndent();
|
115 |
18
| indent().append("</interfaces>").eol();
|
116 |
| } |
117 |
| |
118 |
32
| if (!classfile.getAllFields().isEmpty()) {
|
119 |
20
| indent().append("<fields>").eol();
|
120 |
20
| raiseIndent();
|
121 |
20
| for (Field_info field : classfile.getAllFields()) {
|
122 |
27
| field.accept(this);
|
123 |
| } |
124 |
20
| lowerIndent();
|
125 |
20
| indent().append("</fields>").eol();
|
126 |
| } |
127 |
| |
128 |
32
| if (!classfile.getAllMethods().isEmpty()) {
|
129 |
28
| indent().append("<methods>").eol();
|
130 |
28
| raiseIndent();
|
131 |
28
| for (Method_info method : classfile.getAllMethods()) {
|
132 |
37
| method.accept(this);
|
133 |
| } |
134 |
28
| lowerIndent();
|
135 |
28
| indent().append("</methods>").eol();
|
136 |
| } |
137 |
| |
138 |
32
| if (!classfile.getAttributes().isEmpty()) {
|
139 |
20
| indent().append("<attributes>").eol();
|
140 |
20
| raiseIndent();
|
141 |
20
| for (Attribute_info attribute : classfile.getAttributes()) {
|
142 |
6
| attribute.accept(this);
|
143 |
| } |
144 |
20
| lowerIndent();
|
145 |
20
| indent().append("</attributes>").eol();
|
146 |
| } |
147 |
| |
148 |
32
| lowerIndent();
|
149 |
32
| indent().append("</classfile>").eol();
|
150 |
| } |
151 |
| |
152 |
16
| public void visitConstantPool(ConstantPool constantPool) {
|
153 |
16
| resetCount();
|
154 |
| |
155 |
16
| indent().append("<constant-pool>").eol();
|
156 |
16
| raiseIndent();
|
157 |
| |
158 |
16
| for (ConstantPoolEntry entry : constantPool) {
|
159 |
337
| if (entry != null) {
|
160 |
321
| entry.accept(this);
|
161 |
| } |
162 |
337
| incrementCount();
|
163 |
| } |
164 |
| |
165 |
16
| lowerIndent();
|
166 |
16
| indent().append("</constant-pool>").eol();
|
167 |
| } |
168 |
| |
169 |
114
| public void visitClass_info(Class_info entry) {
|
170 |
114
| if (top) {
|
171 |
48
| top = false;
|
172 |
48
| indent();
|
173 |
48
| append("<class index=\"").append(currentCount()).append("\">");
|
174 |
| |
175 |
48
| append(entry.getName());
|
176 |
48
| append("</class>").eol();
|
177 |
48
| top = true;
|
178 |
| } else { |
179 |
| |
180 |
66
| append(entry.getName());
|
181 |
| } |
182 |
| } |
183 |
| |
184 |
26
| public void visitFieldRef_info(FieldRef_info entry) {
|
185 |
26
| Class_info c = entry.getRawClass();
|
186 |
26
| NameAndType_info nat = entry.getRawNameAndType();
|
187 |
| |
188 |
26
| if (top) {
|
189 |
8
| top = false;
|
190 |
8
| indent();
|
191 |
8
| append("<field-ref-info index=\"").append(currentCount()).append("\">");
|
192 |
8
| append("<class>");
|
193 |
8
| c.accept(this);
|
194 |
8
| append("</class>");
|
195 |
8
| append("<type>");
|
196 |
8
| nat.getRawType().accept(this);
|
197 |
8
| append("</type>");
|
198 |
8
| append("<name>");
|
199 |
8
| nat.getRawName().accept(this);
|
200 |
8
| append("</name>");
|
201 |
8
| append("</field-ref-info>").eol();
|
202 |
8
| top = true;
|
203 |
| } else { |
204 |
18
| append(DescriptorHelper.getType(nat.getType()));
|
205 |
18
| append(" ");
|
206 |
18
| append(entry.getFullSignature());
|
207 |
| } |
208 |
| } |
209 |
| |
210 |
40
| public void visitMethodRef_info(MethodRef_info entry) {
|
211 |
40
| Class_info c = entry.getRawClass();
|
212 |
40
| NameAndType_info nat = entry.getRawNameAndType();
|
213 |
| |
214 |
40
| if (top) {
|
215 |
16
| top = false;
|
216 |
16
| indent();
|
217 |
16
| append("<method-ref-info index=\"").append(currentCount()).append("\">");
|
218 |
16
| append("<class>");
|
219 |
16
| c.accept(this);
|
220 |
16
| append("</class>");
|
221 |
16
| append("<name>");
|
222 |
16
| nat.getRawName().accept(this);
|
223 |
16
| append("</name>");
|
224 |
16
| append("<type>");
|
225 |
16
| nat.getRawType().accept(this);
|
226 |
16
| append("</type>");
|
227 |
16
| append("</method-ref-info>").eol();
|
228 |
16
| top = true;
|
229 |
| } else { |
230 |
24
| if (!entry.isConstructor() && !entry.isStaticInitializer()) {
|
231 |
6
| append(DescriptorHelper.getReturnType(nat.getType())).append(" ");
|
232 |
| } |
233 |
24
| append(entry.getFullSignature());
|
234 |
| } |
235 |
| } |
236 |
| |
237 |
0
| public void visitInterfaceMethodRef_info(InterfaceMethodRef_info entry) {
|
238 |
0
| Class_info c = entry.getRawClass();
|
239 |
0
| NameAndType_info nat = entry.getRawNameAndType();
|
240 |
| |
241 |
0
| if (top) {
|
242 |
0
| top = false;
|
243 |
0
| indent();
|
244 |
0
| append("<interface-method-ref-info index=\"").append(currentCount()).append("\">");
|
245 |
0
| append("<class>");
|
246 |
0
| c.accept(this);
|
247 |
0
| append("</class>");
|
248 |
0
| append("<name>");
|
249 |
0
| nat.getRawName().accept(this);
|
250 |
0
| append("</name>");
|
251 |
0
| append("<type>");
|
252 |
0
| nat.getRawType().accept(this);
|
253 |
0
| append("</type>");
|
254 |
0
| append("</interface-method-ref-info>").eol();
|
255 |
0
| top = true;
|
256 |
| } else { |
257 |
0
| append(DescriptorHelper.getReturnType(nat.getType()));
|
258 |
0
| append(" ");
|
259 |
0
| append(entry.getFullSignature());
|
260 |
| } |
261 |
| } |
262 |
| |
263 |
18
| public void visitString_info(String_info entry) {
|
264 |
18
| if (top) {
|
265 |
6
| top = false;
|
266 |
6
| indent();
|
267 |
6
| append("<string-info index=\"").append(currentCount()).append("\">");
|
268 |
6
| entry.getRawValue().accept(this);
|
269 |
6
| append("</string-info>").eol();
|
270 |
6
| top = true;
|
271 |
| } else { |
272 |
12
| entry.getRawValue().accept(this);
|
273 |
| } |
274 |
| } |
275 |
| |
276 |
22
| public void visitInteger_info(Integer_info entry) {
|
277 |
22
| if (top) {
|
278 |
9
| top = false;
|
279 |
9
| indent();
|
280 |
9
| append("<integer-info index=\"").append(currentCount()).append("\">");
|
281 |
9
| append(entry.getValue());
|
282 |
9
| append("</integer-info>").eol();
|
283 |
9
| top = true;
|
284 |
| } else { |
285 |
13
| append(entry.getValue());
|
286 |
| } |
287 |
| } |
288 |
| |
289 |
2
| public void visitFloat_info(Float_info entry) {
|
290 |
2
| if (top) {
|
291 |
1
| top = false;
|
292 |
1
| indent();
|
293 |
1
| append("<float-info index=\"").append(currentCount()).append("\">");
|
294 |
1
| append(entry.getValue());
|
295 |
1
| append("</float-info>").eol();
|
296 |
1
| top = true;
|
297 |
| } else { |
298 |
1
| append(entry.getValue());
|
299 |
| } |
300 |
| } |
301 |
| |
302 |
0
| public void visitLong_info(Long_info entry) {
|
303 |
0
| if (top) {
|
304 |
0
| top = false;
|
305 |
0
| indent();
|
306 |
0
| append("<long-info index=\"").append(currentCount()).append("\">");
|
307 |
0
| append(entry.getValue());
|
308 |
0
| append("</long-info>").eol();
|
309 |
0
| top = true;
|
310 |
| } else { |
311 |
0
| append(entry.getValue());
|
312 |
| } |
313 |
| } |
314 |
| |
315 |
0
| public void visitDouble_info(Double_info entry) {
|
316 |
0
| if (top) {
|
317 |
0
| top = false;
|
318 |
0
| indent();
|
319 |
0
| append("<double-info index=\"").append(currentCount()).append("\">");
|
320 |
0
| append(entry.getValue());
|
321 |
0
| append("</double-info>").eol();
|
322 |
0
| top = true;
|
323 |
| } else { |
324 |
0
| append(entry.getValue());
|
325 |
| } |
326 |
| } |
327 |
| |
328 |
24
| public void visitNameAndType_info(NameAndType_info entry) {
|
329 |
24
| if (top) {
|
330 |
24
| top = false;
|
331 |
24
| indent();
|
332 |
24
| append("<name-and-type-info index=\"").append(currentCount()).append("\">");
|
333 |
24
| append("<name>");
|
334 |
24
| entry.getRawName().accept(this);
|
335 |
24
| append("</name>");
|
336 |
24
| append("<type>");
|
337 |
24
| entry.getRawType().accept(this);
|
338 |
24
| append("</type>");
|
339 |
24
| append("</name-and-type-info>").eol();
|
340 |
24
| top = true;
|
341 |
| } else { |
342 |
0
| entry.getRawName().accept(this);
|
343 |
0
| append(" ");
|
344 |
0
| entry.getRawType().accept(this);
|
345 |
| } |
346 |
| } |
347 |
| |
348 |
397
| public void visitUTF8_info(UTF8_info entry) {
|
349 |
397
| if (top) {
|
350 |
209
| top = false;
|
351 |
209
| indent().append("<utf8-info index=\"").append(currentCount()).append("\">");
|
352 |
209
| append(escapeXMLCharacters(entry.getValue()));
|
353 |
209
| append("</utf8-info>").eol();
|
354 |
209
| top = true;
|
355 |
| } else { |
356 |
188
| append(escapeXMLCharacters(entry.getValue()));
|
357 |
| } |
358 |
| } |
359 |
| |
360 |
45
| public void visitField_info(Field_info entry) {
|
361 |
45
| indent().append("<field-info access-flag=\"").append(format.format(entry.getAccessFlag())).append("\">").eol();
|
362 |
45
| raiseIndent();
|
363 |
| |
364 |
28
| if (entry.isPublic()) indent().append("<public/>").eol();
|
365 |
1
| if (entry.isProtected()) indent().append("<protected/>").eol();
|
366 |
1
| if (entry.isPrivate()) indent().append("<private/>").eol();
|
367 |
21
| if (entry.isStatic()) indent().append("<static/>").eol();
|
368 |
21
| if (entry.isFinal()) indent().append("<final/>").eol();
|
369 |
1
| if (entry.isVolatile()) indent().append("<volatile/>").eol();
|
370 |
1
| if (entry.isTransient()) indent().append("<transient/>").eol();
|
371 |
1
| if (entry.isSynthetic()) indent().append("<synthetic/>").eol();
|
372 |
1
| if (entry.isEnum()) indent().append("<enum/>").eol();
|
373 |
| |
374 |
45
| indent();
|
375 |
45
| append("<name>");
|
376 |
45
| entry.getRawName().accept(this);
|
377 |
45
| append("</name>").eol();
|
378 |
| |
379 |
45
| indent().append("<type>").append(entry.getType()).append("</type>").eol();
|
380 |
| |
381 |
45
| if (!entry.getAttributes().isEmpty()) {
|
382 |
39
| indent().append("<attributes>").eol();
|
383 |
39
| raiseIndent();
|
384 |
39
| super.visitField_info(entry);
|
385 |
39
| lowerIndent();
|
386 |
39
| indent().append("</attributes>").eol();
|
387 |
| } |
388 |
| |
389 |
45
| lowerIndent();
|
390 |
45
| indent().append("</field-info>").eol();
|
391 |
| } |
392 |
| |
393 |
61
| public void visitMethod_info(Method_info entry) {
|
394 |
61
| indent().append("<method-info access-flag=\"").append(format.format(entry.getAccessFlag())).append("\">").eol();
|
395 |
61
| raiseIndent();
|
396 |
| |
397 |
37
| if (entry.isPublic()) indent().append("<public/>").eol();
|
398 |
1
| if (entry.isProtected()) indent().append("<protected/>").eol();
|
399 |
2
| if (entry.isPrivate()) indent().append("<private/>").eol();
|
400 |
3
| if (entry.isStatic()) indent().append("<static/>").eol();
|
401 |
1
| if (entry.isFinal()) indent().append("<final/>").eol();
|
402 |
1
| if (entry.isSynchronized()) indent().append("<synchronized/>").eol();
|
403 |
1
| if (entry.isBridge()) indent().append("<bridge/>").eol();
|
404 |
1
| if (entry.isVarargs()) indent().append("<varargs/>").eol();
|
405 |
1
| if (entry.isNative()) indent().append("<native/>").eol();
|
406 |
8
| if (entry.isAbstract()) indent().append("<abstract/>").eol();
|
407 |
1
| if (entry.isStrict()) indent().append("<strict/>").eol();
|
408 |
1
| if (entry.isSynthetic()) indent().append("<synthetic/>").eol();
|
409 |
| |
410 |
61
| indent();
|
411 |
61
| append("<name>");
|
412 |
61
| entry.getRawName().accept(this);
|
413 |
61
| append("</name>").eol();
|
414 |
| |
415 |
61
| if (!entry.getName().equals("<init>") && !entry.getName().equals("<clinit>")) {
|
416 |
45
| indent().append("<return-type>").append((entry.getReturnType() != null) ? entry.getReturnType() : "void").append("</return-type>").eol();
|
417 |
| } |
418 |
61
| indent().append("<signature>").append(entry.getSignature()).append("</signature>").eol();
|
419 |
| |
420 |
61
| if (!entry.getAttributes().isEmpty()) {
|
421 |
55
| indent().append("<attributes>").eol();
|
422 |
55
| raiseIndent();
|
423 |
55
| super.visitMethod_info(entry);
|
424 |
55
| lowerIndent();
|
425 |
55
| indent().append("</attributes>").eol();
|
426 |
| } |
427 |
| |
428 |
61
| lowerIndent();
|
429 |
61
| indent().append("</method-info>").eol();
|
430 |
| } |
431 |
| |
432 |
20
| public void visitConstantValue_attribute(ConstantValue_attribute attribute) {
|
433 |
20
| indent().append("<constant-value-attribute>");
|
434 |
| |
435 |
20
| attribute.getRawValue().accept(this);
|
436 |
| |
437 |
20
| append("</constant-value-attribute>").eol();
|
438 |
| } |
439 |
| |
440 |
30
| public void visitCode_attribute(Code_attribute attribute) {
|
441 |
30
| indent().append("<code-attribute>").eol();
|
442 |
30
| raiseIndent();
|
443 |
| |
444 |
30
| indent().append("<length>").append(attribute.getCode().length).append("</length>").eol();
|
445 |
| |
446 |
30
| indent().append("<instructions>").eol();
|
447 |
30
| raiseIndent();
|
448 |
30
| for (Instruction instruction : attribute) {
|
449 |
157
| instruction.accept(this);
|
450 |
| } |
451 |
30
| lowerIndent();
|
452 |
30
| indent().append("</instructions>").eol();
|
453 |
| |
454 |
30
| if (!attribute.getExceptionHandlers().isEmpty()) {
|
455 |
2
| indent().append("<exception-handlers>").eol();
|
456 |
2
| raiseIndent();
|
457 |
2
| for (ExceptionHandler exceptionHandler : attribute.getExceptionHandlers()) {
|
458 |
2
| exceptionHandler.accept(this);
|
459 |
| } |
460 |
2
| lowerIndent();
|
461 |
2
| indent().append("</exception-handlers>").eol();
|
462 |
| } |
463 |
| |
464 |
30
| if (!attribute.getAttributes().isEmpty()) {
|
465 |
4
| indent().append("<attributes>").eol();
|
466 |
4
| raiseIndent();
|
467 |
4
| for (Attribute_info attribute_info : attribute.getAttributes()) {
|
468 |
10
| attribute_info.accept(this);
|
469 |
| } |
470 |
4
| lowerIndent();
|
471 |
4
| indent().append("</attributes>").eol();
|
472 |
| } |
473 |
| |
474 |
30
| lowerIndent();
|
475 |
30
| indent().append("</code-attribute>").eol();
|
476 |
| } |
477 |
| |
478 |
0
| public void visitExceptions_attribute(Exceptions_attribute attribute) {
|
479 |
0
| indent().append("<exceptions-attribute>").eol();
|
480 |
0
| raiseIndent();
|
481 |
| |
482 |
0
| for (Class_info exception : attribute.getExceptions()) {
|
483 |
0
| indent();
|
484 |
0
| append("<exception>");
|
485 |
0
| exception.accept(this);
|
486 |
0
| append("</exception>").eol();
|
487 |
| } |
488 |
| |
489 |
0
| lowerIndent();
|
490 |
0
| indent().append("</exceptions-attribute>").eol();
|
491 |
| } |
492 |
| |
493 |
2
| public void visitInnerClasses_attribute(InnerClasses_attribute attribute) {
|
494 |
2
| indent().append("<inner-classes-attribute>").eol();
|
495 |
2
| raiseIndent();
|
496 |
| |
497 |
2
| super.visitInnerClasses_attribute(attribute);
|
498 |
| |
499 |
2
| lowerIndent();
|
500 |
2
| indent().append("</inner-classes-attribute>").eol();
|
501 |
| } |
502 |
| |
503 |
0
| public void visitEnclosingMethod_attribute(EnclosingMethod_attribute attribute) {
|
504 |
0
| indent().append("<enclosing-method-attribute>").eol();
|
505 |
0
| raiseIndent();
|
506 |
| |
507 |
0
| indent().append("<class>");
|
508 |
0
| attribute.getRawClassInfo().accept(this);
|
509 |
0
| append("</class>").eol();
|
510 |
| |
511 |
0
| indent().append("<method>");
|
512 |
0
| if (attribute.getMethodIndex() != 0) {
|
513 |
0
| NameAndType_info nat = attribute.getRawMethod();
|
514 |
0
| append(DescriptorHelper.getReturnType(nat.getType())).append(" ").append(nat.getName()).append(DescriptorHelper.getSignature(nat.getType()));
|
515 |
| } |
516 |
0
| append("</method>").eol();
|
517 |
| |
518 |
0
| lowerIndent();
|
519 |
0
| indent().append("</enclosing-method-attribute>").eol();
|
520 |
| } |
521 |
| |
522 |
0
| public void visitSynthetic_attribute(Synthetic_attribute attribute) {
|
523 |
0
| indent().append("<synthetic-attribute/>").eol();
|
524 |
| } |
525 |
| |
526 |
0
| public void visitSignature_attribute(Signature_attribute attribute) {
|
527 |
0
| indent().append("<signature-attribute>");
|
528 |
0
| attribute.getRawSignature().accept(this);
|
529 |
0
| append("</signature-attribute>").eol();
|
530 |
| } |
531 |
| |
532 |
2
| public void visitSourceFile_attribute(SourceFile_attribute attribute) {
|
533 |
2
| indent().append("<source-file-attribute>").append(attribute.getSourceFile()).append("</source-file-attribute>").eol();
|
534 |
| } |
535 |
| |
536 |
4
| public void visitLineNumberTable_attribute(LineNumberTable_attribute attribute) {
|
537 |
4
| indent().append("<line-number-table-attribute>").eol();
|
538 |
4
| raiseIndent();
|
539 |
| |
540 |
4
| super.visitLineNumberTable_attribute(attribute);
|
541 |
| |
542 |
4
| lowerIndent();
|
543 |
4
| indent().append("</line-number-table-attribute>").eol();
|
544 |
| } |
545 |
| |
546 |
4
| public void visitLocalVariableTable_attribute(LocalVariableTable_attribute attribute) {
|
547 |
4
| indent().append("<local-variable-table-attribute>").eol();
|
548 |
4
| raiseIndent();
|
549 |
| |
550 |
4
| super.visitLocalVariableTable_attribute(attribute);
|
551 |
| |
552 |
4
| lowerIndent();
|
553 |
4
| indent().append("</local-variable-table-attribute>").eol();
|
554 |
| } |
555 |
| |
556 |
0
| public void visitLocalVariableTypeTable_attribute(LocalVariableTypeTable_attribute attribute) {
|
557 |
0
| indent().append("<local-variable-type-table-attribute>").eol();
|
558 |
0
| raiseIndent();
|
559 |
| |
560 |
0
| super.visitLocalVariableTypeTable_attribute(attribute);
|
561 |
| |
562 |
0
| lowerIndent();
|
563 |
0
| indent().append("</local-variable-type-table-attribute>").eol();
|
564 |
| } |
565 |
| |
566 |
7
| public void visitDeprecated_attribute(Deprecated_attribute attribute) {
|
567 |
7
| indent().append("<deprecated-attribute/>").eol();
|
568 |
| } |
569 |
| |
570 |
2
| public void visitRuntimeVisibleAnnotations_attribute(RuntimeVisibleAnnotations_attribute attribute) {
|
571 |
2
| indent().append("<runtime-visible-annotations-attribute>").eol();
|
572 |
2
| raiseIndent();
|
573 |
| |
574 |
2
| super.visitRuntimeVisibleAnnotations_attribute(attribute);
|
575 |
| |
576 |
2
| lowerIndent();
|
577 |
2
| indent().append("</runtime-visible-annotations-attribute>").eol();
|
578 |
| } |
579 |
| |
580 |
2
| public void visitRuntimeInvisibleAnnotations_attribute(RuntimeInvisibleAnnotations_attribute attribute) {
|
581 |
2
| indent().append("<runtime-invisible-annotations-attribute>").eol();
|
582 |
2
| raiseIndent();
|
583 |
| |
584 |
2
| super.visitRuntimeInvisibleAnnotations_attribute(attribute);
|
585 |
| |
586 |
2
| lowerIndent();
|
587 |
2
| indent().append("</runtime-invisible-annotations-attribute>").eol();
|
588 |
| } |
589 |
| |
590 |
4
| protected void visitRuntimeAnnotations_attribute(RuntimeAnnotations_attribute attribute) {
|
591 |
4
| indent().append("<annotations>").eol();
|
592 |
4
| raiseIndent();
|
593 |
| |
594 |
4
| super.visitRuntimeAnnotations_attribute(attribute);
|
595 |
| |
596 |
4
| lowerIndent();
|
597 |
4
| indent().append("</annotations>").eol();
|
598 |
| } |
599 |
| |
600 |
2
| public void visitRuntimeVisibleParameterAnnotations_attribute(RuntimeVisibleParameterAnnotations_attribute attribute) {
|
601 |
2
| indent().append("<runtime-visible-parameter-annotations-attribute>").eol();
|
602 |
2
| raiseIndent();
|
603 |
| |
604 |
2
| super.visitRuntimeVisibleParameterAnnotations_attribute(attribute);
|
605 |
| |
606 |
2
| lowerIndent();
|
607 |
2
| indent().append("</runtime-visible-parameter-annotations-attribute>").eol();
|
608 |
| } |
609 |
| |
610 |
2
| public void visitRuntimeInvisibleParameterAnnotations_attribute(RuntimeInvisibleParameterAnnotations_attribute attribute) {
|
611 |
2
| indent().append("<runtime-invisible-parameter-annotations-attribute>").eol();
|
612 |
2
| raiseIndent();
|
613 |
| |
614 |
2
| super.visitRuntimeInvisibleParameterAnnotations_attribute(attribute);
|
615 |
| |
616 |
2
| lowerIndent();
|
617 |
2
| indent().append("</runtime-invisible-parameter-annotations-attribute>").eol();
|
618 |
| } |
619 |
| |
620 |
4
| protected void visitRuntimeParameterAnnotations_attribute(RuntimeParameterAnnotations_attribute attribute) {
|
621 |
4
| indent().append("<parameter-annotations>").eol();
|
622 |
4
| raiseIndent();
|
623 |
| |
624 |
4
| super.visitRuntimeParameterAnnotations_attribute(attribute);
|
625 |
| |
626 |
4
| lowerIndent();
|
627 |
4
| indent().append("</parameter-annotations>").eol();
|
628 |
| } |
629 |
| |
630 |
1
| public void visitAnnotationDefault_attribute(AnnotationDefault_attribute attribute) {
|
631 |
1
| indent().append("<annotation-default-attribute>").eol();
|
632 |
1
| raiseIndent();
|
633 |
| |
634 |
1
| super.visitAnnotationDefault_attribute(attribute);
|
635 |
| |
636 |
1
| lowerIndent();
|
637 |
1
| indent().append("</annotation-default-attribute>").eol();
|
638 |
| } |
639 |
| |
640 |
2
| public void visitCustom_attribute(Custom_attribute attribute) {
|
641 |
2
| indent().append("<custom-attribute name=\"").append(escapeXMLCharacters(attribute.getName())).append("\">").append(Hex.toString(attribute.getInfo())).append("</custom-attribute>").eol();
|
642 |
| } |
643 |
| |
644 |
157
| public void visitInstruction(Instruction instruction) {
|
645 |
157
| indent();
|
646 |
157
| append("<instruction pc=\"").append(instruction.getStart()).append("\" length=\"").append(instruction.getLength()).append("\"");
|
647 |
157
| switch (instruction.getOpcode()) {
|
648 |
0
| case 0x02:
|
649 |
1
| case 0x03:
|
650 |
8
| case 0x04:
|
651 |
0
| case 0x05:
|
652 |
0
| case 0x06:
|
653 |
1
| case 0x07:
|
654 |
0
| case 0x08:
|
655 |
0
| case 0x09:
|
656 |
0
| case 0x0a:
|
657 |
0
| case 0x0b:
|
658 |
0
| case 0x0c:
|
659 |
0
| case 0x0d:
|
660 |
0
| case 0x0e:
|
661 |
0
| case 0x0f:
|
662 |
10
| append(" value=\"").append(instruction.getValue()).append("\">");
|
663 |
10
| append(instruction);
|
664 |
10
| break;
|
665 |
0
| case 0x10:
|
666 |
2
| case 0x11:
|
667 |
2
| append(" value=\"").append(instruction.getValue()).append("\">");
|
668 |
2
| append(instruction).append(" ").append(instruction.getValue());
|
669 |
2
| break;
|
670 |
6
| case 0x12:
|
671 |
0
| case 0x13:
|
672 |
0
| case 0x14:
|
673 |
10
| case 0xb2:
|
674 |
0
| case 0xb3:
|
675 |
8
| case 0xb4:
|
676 |
0
| case 0xb5:
|
677 |
4
| case 0xb6:
|
678 |
18
| case 0xb7:
|
679 |
2
| case 0xb8:
|
680 |
0
| case 0xb9:
|
681 |
2
| case 0xbb:
|
682 |
0
| case 0xbd:
|
683 |
0
| case 0xc0:
|
684 |
0
| case 0xc1:
|
685 |
0
| case 0xc5:
|
686 |
50
| append(" index=\"").append(instruction.getIndex()).append("\">");
|
687 |
50
| append(instruction);
|
688 |
50
| append(" ");
|
689 |
50
| instruction.getIndexedConstantPoolEntry().accept(this);
|
690 |
50
| break;
|
691 |
0
| case 0x1a:
|
692 |
0
| case 0x1e:
|
693 |
0
| case 0x22:
|
694 |
0
| case 0x26:
|
695 |
18
| case 0x2a:
|
696 |
0
| case 0x3b:
|
697 |
0
| case 0x3f:
|
698 |
0
| case 0x43:
|
699 |
0
| case 0x47:
|
700 |
0
| case 0x4b:
|
701 |
0
| case 0x1b:
|
702 |
0
| case 0x1f:
|
703 |
2
| case 0x23:
|
704 |
0
| case 0x27:
|
705 |
2
| case 0x2b:
|
706 |
1
| case 0x3c:
|
707 |
0
| case 0x40:
|
708 |
0
| case 0x44:
|
709 |
0
| case 0x48:
|
710 |
4
| case 0x4c:
|
711 |
0
| case 0x1c:
|
712 |
0
| case 0x20:
|
713 |
0
| case 0x24:
|
714 |
0
| case 0x28:
|
715 |
0
| case 0x2c:
|
716 |
0
| case 0x3d:
|
717 |
0
| case 0x41:
|
718 |
1
| case 0x45:
|
719 |
0
| case 0x49:
|
720 |
0
| case 0x4d:
|
721 |
0
| case 0x1d:
|
722 |
0
| case 0x21:
|
723 |
0
| case 0x25:
|
724 |
0
| case 0x29:
|
725 |
0
| case 0x2d:
|
726 |
0
| case 0x3e:
|
727 |
0
| case 0x42:
|
728 |
0
| case 0x46:
|
729 |
0
| case 0x4a:
|
730 |
0
| case 0x4e:
|
731 |
0
| case 0x15:
|
732 |
0
| case 0x16:
|
733 |
0
| case 0x17:
|
734 |
0
| case 0x18:
|
735 |
0
| case 0x19:
|
736 |
0
| case 0x36:
|
737 |
0
| case 0x37:
|
738 |
0
| case 0x38:
|
739 |
0
| case 0x39:
|
740 |
0
| case 0x3a:
|
741 |
0
| case 0xa9:
|
742 |
28
| append(" index=\"").append(instruction.getIndex()).append("\">");
|
743 |
28
| append(instruction);
|
744 |
28
| appendLocalVariable(instruction.getIndexedLocalVariable());
|
745 |
28
| break;
|
746 |
0
| case 0x99:
|
747 |
0
| case 0x9a:
|
748 |
0
| case 0x9b:
|
749 |
0
| case 0x9c:
|
750 |
0
| case 0x9d:
|
751 |
0
| case 0x9e:
|
752 |
0
| case 0x9f:
|
753 |
0
| case 0xa0:
|
754 |
0
| case 0xa1:
|
755 |
0
| case 0xa2:
|
756 |
0
| case 0xa3:
|
757 |
0
| case 0xa4:
|
758 |
0
| case 0xa5:
|
759 |
0
| case 0xa6:
|
760 |
2
| case 0xa7:
|
761 |
0
| case 0xa8:
|
762 |
0
| case 0xc6:
|
763 |
0
| case 0xc7:
|
764 |
0
| case 0xc8:
|
765 |
0
| case 0xc9:
|
766 |
2
| append(" offset=\"").append(instruction.getOffset()).append("\">");
|
767 |
2
| append(instruction).append(" ").append(instruction.getStart() + instruction.getOffset());
|
768 |
2
| break;
|
769 |
0
| case 0x84:
|
770 |
0
| append(" index=\"").append(instruction.getIndex()).append("\" value=\"").append(instruction.getValue()).append("\">");
|
771 |
0
| append(instruction);
|
772 |
0
| appendLocalVariable(instruction.getIndexedLocalVariable());
|
773 |
0
| break;
|
774 |
0
| case 0xc4:
|
775 |
0
| if (instruction.getByte(1) == 0x84 ) {
|
776 |
0
| append(" index=\"").append(instruction.getIndex()).append("\" value=\"").append(instruction.getValue()).append("\">");
|
777 |
| } else { |
778 |
0
| append(" index=\"").append(instruction.getIndex()).append("\">");
|
779 |
| } |
780 |
0
| append(instruction);
|
781 |
0
| appendLocalVariable(instruction.getIndexedLocalVariable());
|
782 |
0
| break;
|
783 |
65
| default:
|
784 |
65
| append(">");
|
785 |
65
| append(instruction);
|
786 |
65
| break;
|
787 |
| } |
788 |
157
| append("</instruction>").eol();
|
789 |
| } |
790 |
| |
791 |
2
| public void visitExceptionHandler(ExceptionHandler helper) {
|
792 |
2
| indent();
|
793 |
2
| append("<exception-handler>");
|
794 |
2
| append("<start-pc>").append(helper.getStartPC()).append("</start-pc>");
|
795 |
2
| append("<end-pc>").append(helper.getEndPC()).append("</end-pc>");
|
796 |
2
| append("<handler-pc>").append(helper.getHandlerPC()).append("</handler-pc>");
|
797 |
| |
798 |
2
| append("<catch-type>");
|
799 |
2
| if (helper.getCatchTypeIndex() != 0) {
|
800 |
2
| helper.getRawCatchType().accept(this);
|
801 |
| } |
802 |
2
| append("</catch-type>");
|
803 |
| |
804 |
2
| append("</exception-handler>").eol();
|
805 |
| } |
806 |
| |
807 |
22
| public void visitInnerClass(InnerClass helper) {
|
808 |
22
| indent().append("<inner-class access-flag=\"").append(format.format(helper.getAccessFlag())).append("\">").eol();
|
809 |
22
| raiseIndent();
|
810 |
| |
811 |
3
| if (helper.isPublic()) indent().append("<public/>").eol();
|
812 |
1
| if (helper.isProtected()) indent().append("<protected/>").eol();
|
813 |
1
| if (helper.isPrivate()) indent().append("<private/>").eol();
|
814 |
3
| if (helper.isStatic()) indent().append("<static/>").eol();
|
815 |
1
| if (helper.isFinal()) indent().append("<final/>").eol();
|
816 |
1
| if (helper.isInterface()) indent().append("<is-interface/>").eol();
|
817 |
1
| if (helper.isAbstract()) indent().append("<abstract/>").eol();
|
818 |
1
| if (helper.isSynthetic()) indent().append("<synthetic/>").eol();
|
819 |
1
| if (helper.isAnnotation()) indent().append("<is-annotation/>").eol();
|
820 |
1
| if (helper.isEnum()) indent().append("<enum/>").eol();
|
821 |
| |
822 |
22
| indent();
|
823 |
22
| append("<inner-class-info>");
|
824 |
22
| if (helper.getInnerClassInfoIndex() != 0) {
|
825 |
2
| helper.getRawInnerClassInfo().accept(this);
|
826 |
| } |
827 |
22
| append("</inner-class-info>").eol();
|
828 |
| |
829 |
22
| indent();
|
830 |
22
| append("<outer-class-info>");
|
831 |
22
| if (helper.getOuterClassInfoIndex() != 0) {
|
832 |
2
| helper.getRawOuterClassInfo().accept(this);
|
833 |
| } |
834 |
22
| append("</outer-class-info>").eol();
|
835 |
| |
836 |
22
| indent();
|
837 |
22
| append("<inner-name>");
|
838 |
22
| if (helper.getInnerNameIndex() != 0) {
|
839 |
2
| helper.getRawInnerName().accept(this);
|
840 |
| } |
841 |
22
| append("</inner-name>").eol();
|
842 |
| |
843 |
22
| lowerIndent();
|
844 |
22
| indent().append("</inner-class>").eol();
|
845 |
| } |
846 |
| |
847 |
16
| public void visitLineNumber(LineNumber helper) {
|
848 |
16
| indent();
|
849 |
16
| append("<line-number>");
|
850 |
16
| append("<start-pc>").append(helper.getStartPC()).append("</start-pc>");
|
851 |
16
| append("<line>").append(helper.getLineNumber()).append("</line>");
|
852 |
16
| append("</line-number>").eol();
|
853 |
| } |
854 |
| |
855 |
9
| public void visitLocalVariable(LocalVariable helper) {
|
856 |
9
| indent();
|
857 |
9
| append("<local-variable pc=\"").append(helper.getStartPC()).append("\" length=\"").append(helper.getLength()).append("\" index=\"").append(helper.getIndex()).append("\">");
|
858 |
9
| append("<name>");
|
859 |
9
| helper.getRawName().accept(this);
|
860 |
9
| append("</name>");
|
861 |
| |
862 |
9
| append("<type>").append(DescriptorHelper.getType(helper.getDescriptor())).append("</type>");
|
863 |
9
| append("</local-variable>").eol();
|
864 |
| } |
865 |
| |
866 |
1
| public void visitLocalVariableType(LocalVariableType helper) {
|
867 |
1
| indent();
|
868 |
1
| append("<local-variable-type pc=\"").append(helper.getStartPC()).append("\" length=\"").append(helper.getLength()).append("\" index=\"").append(helper.getIndex()).append("\">");
|
869 |
1
| append("<name>");
|
870 |
1
| helper.getRawName().accept(this);
|
871 |
1
| append("</name>");
|
872 |
| |
873 |
1
| append("<signature>");
|
874 |
1
| helper.getRawSignature().accept(this);
|
875 |
1
| append("</signature>");
|
876 |
1
| append("</local-variable-type>").eol();
|
877 |
| } |
878 |
| |
879 |
2
| public void visitParameter(Parameter helper) {
|
880 |
2
| indent().append("<parameter>").eol();
|
881 |
2
| raiseIndent();
|
882 |
| |
883 |
2
| indent().append("<annotations>").eol();
|
884 |
2
| raiseIndent();
|
885 |
| |
886 |
2
| super.visitParameter(helper);
|
887 |
| |
888 |
2
| lowerIndent();
|
889 |
2
| indent().append("</annotations>").eol();
|
890 |
| |
891 |
2
| lowerIndent();
|
892 |
2
| indent().append("</parameter>").eol();
|
893 |
| } |
894 |
| |
895 |
2
| public void visitAnnotation(Annotation helper) {
|
896 |
2
| indent().append("<annotation>").eol();
|
897 |
2
| raiseIndent();
|
898 |
| |
899 |
2
| indent().append("<type>").append(helper.getType()).append("</type>").eol();
|
900 |
| |
901 |
2
| indent().append("<element-value-pairs>").eol();
|
902 |
2
| raiseIndent();
|
903 |
| |
904 |
2
| super.visitAnnotation(helper);
|
905 |
| |
906 |
2
| lowerIndent();
|
907 |
2
| indent().append("</element-value-pairs>").eol();
|
908 |
| |
909 |
2
| lowerIndent();
|
910 |
2
| indent().append("</annotation>").eol();
|
911 |
| } |
912 |
| |
913 |
1
| public void visitElementValuePair(ElementValuePair helper) {
|
914 |
1
| indent().append("<element-value-pair>").eol();
|
915 |
1
| raiseIndent();
|
916 |
| |
917 |
1
| indent().append("<element-name>").append(helper.getElementName()).append("</element-name>").eol();
|
918 |
| |
919 |
1
| super.visitElementValuePair(helper);
|
920 |
| |
921 |
1
| lowerIndent();
|
922 |
1
| indent().append("</element-value-pair>").eol();
|
923 |
| } |
924 |
| |
925 |
1
| public void visitByteConstantElementValue(ByteConstantElementValue helper) {
|
926 |
1
| visitConstantElementValue(helper, "byte");
|
927 |
| } |
928 |
| |
929 |
1
| public void visitCharConstantElementValue(CharConstantElementValue helper) {
|
930 |
1
| visitConstantElementValue(helper, "char");
|
931 |
| } |
932 |
| |
933 |
1
| public void visitDoubleConstantElementValue(DoubleConstantElementValue helper) {
|
934 |
1
| visitConstantElementValue(helper, "double");
|
935 |
| } |
936 |
| |
937 |
1
| public void visitFloatConstantElementValue(FloatConstantElementValue helper) {
|
938 |
1
| visitConstantElementValue(helper, "float");
|
939 |
| } |
940 |
| |
941 |
1
| public void visitIntegerConstantElementValue(IntegerConstantElementValue helper) {
|
942 |
1
| visitConstantElementValue(helper, "integer");
|
943 |
| } |
944 |
| |
945 |
1
| public void visitLongConstantElementValue(LongConstantElementValue helper) {
|
946 |
1
| visitConstantElementValue(helper, "long");
|
947 |
| } |
948 |
| |
949 |
1
| public void visitShortConstantElementValue(ShortConstantElementValue helper) {
|
950 |
1
| visitConstantElementValue(helper, "short");
|
951 |
| } |
952 |
| |
953 |
1
| public void visitBooleanConstantElementValue(BooleanConstantElementValue helper) {
|
954 |
1
| visitConstantElementValue(helper, "boolean");
|
955 |
| } |
956 |
| |
957 |
1
| public void visitStringConstantElementValue(StringConstantElementValue helper) {
|
958 |
1
| visitConstantElementValue(helper, "string");
|
959 |
| } |
960 |
| |
961 |
9
| private void visitConstantElementValue(ConstantElementValue helper, String type) {
|
962 |
9
| indent();
|
963 |
9
| append("<").append(type).append("-element-value tag=\"").append(helper.getTag()).append("\">");
|
964 |
9
| helper.getRawConstValue().accept(this);
|
965 |
9
| append("</").append(type).append("-element-value>").eol();
|
966 |
| } |
967 |
| |
968 |
1
| public void visitEnumElementValue(EnumElementValue helper) {
|
969 |
1
| indent();
|
970 |
1
| append("<enum-element-value tag=\"").append(helper.getTag()).append("\">");
|
971 |
1
| append(helper.getTypeName()).append(".").append(helper.getConstName());
|
972 |
1
| append("</enum-element-value>").eol();
|
973 |
| } |
974 |
| |
975 |
1
| public void visitClassElementValue(ClassElementValue helper) {
|
976 |
1
| indent();
|
977 |
1
| append("<class-element-value tag=\"").append(helper.getTag()).append("\">");
|
978 |
1
| append(helper.getClassInfo());
|
979 |
1
| append("</class-element-value>").eol();
|
980 |
| } |
981 |
| |
982 |
1
| public void visitAnnotationElementValue(AnnotationElementValue helper) {
|
983 |
1
| indent().append("<annotation-element-value tag=\"").append(helper.getTag()).append("\">").eol();
|
984 |
1
| raiseIndent();
|
985 |
| |
986 |
1
| super.visitAnnotationElementValue(helper);
|
987 |
| |
988 |
1
| lowerIndent();
|
989 |
1
| indent().append("</annotation-element-value>").eol();
|
990 |
| } |
991 |
| |
992 |
1
| public void visitArrayElementValue(ArrayElementValue helper) {
|
993 |
1
| indent().append("<array-element-value tag=\"").append(helper.getTag()).append("\">").eol();
|
994 |
1
| raiseIndent();
|
995 |
| |
996 |
1
| super.visitArrayElementValue(helper);
|
997 |
| |
998 |
1
| lowerIndent();
|
999 |
1
| indent().append("</array-element-value>").eol();
|
1000 |
| } |
1001 |
| |
1002 |
28
| private void appendLocalVariable(LocalVariable localVariable) {
|
1003 |
28
| if (localVariable != null) {
|
1004 |
8
| append(" ");
|
1005 |
8
| append(DescriptorHelper.getType(localVariable.getDescriptor())).append(" ").append(localVariable.getName());
|
1006 |
| } |
1007 |
| } |
1008 |
| |
1009 |
404
| @VisibleForTesting
|
1010 |
| String escapeXMLCharacters(String text) { |
1011 |
404
| StringBuilder result = new StringBuilder();
|
1012 |
404
| boolean containsControlCharacters = false;
|
1013 |
| |
1014 |
404
| for (int i=0; i<text.length(); i++) {
|
1015 |
4618
| char c = text.charAt(i);
|
1016 |
4618
| if (c == '&') {
|
1017 |
4
| result.append("&");
|
1018 |
4614
| } else if (c == '<') {
|
1019 |
51
| result.append("<");
|
1020 |
4563
| } else if (c == '>') {
|
1021 |
51
| result.append(">");
|
1022 |
4512
| } else if (Character.isISOControl(c) || c > 0x9F) {
|
1023 |
7
| containsControlCharacters = true;
|
1024 |
7
| result.append("&#x");
|
1025 |
7
| result.append(Integer.toString(c, 16).toUpperCase());
|
1026 |
7
| result.append(";");
|
1027 |
| } else { |
1028 |
4505
| result.append(c);
|
1029 |
| } |
1030 |
| } |
1031 |
| |
1032 |
404
| if (containsControlCharacters) {
|
1033 |
7
| return "<![CDATA[" + result.toString() + "]]>";
|
1034 |
| } else { |
1035 |
397
| return result.toString();
|
1036 |
| } |
1037 |
| } |
1038 |
| } |