1 32 33 package com.jeantessier.classreader; 34 35 import java.io.*; 36 import java.util.*; 37 38 import org.apache.oro.text.perl.*; 39 40 public class XMLPrinter extends Printer { 41 public static final String DEFAULT_ENCODING = "utf-8"; 42 public static final String DEFAULT_DTD_PREFIX = "http://depfind.sourceforge.net/dtd"; 43 44 private static final BitFormat format = new BitFormat(16); 45 private static final Perl5Util perl = new Perl5Util(); 46 47 private boolean top = true; 48 49 public XMLPrinter(PrintWriter out) { 50 this(out, DEFAULT_ENCODING, DEFAULT_DTD_PREFIX); 51 } 52 53 public XMLPrinter(PrintWriter out, String encoding, String dtdPrefix) { 54 super(out); 55 56 appendHeader(encoding, dtdPrefix); 57 } 58 59 private void appendHeader(String encoding, String dtdPrefix) { 60 append("<?xml version=\"1.0\" encoding=\"").append(encoding).append("\" ?>").eol(); 61 eol(); 62 append("<!DOCTYPE classfiles SYSTEM \"").append(dtdPrefix).append("/classfile.dtd\">").eol(); 63 eol(); 64 } 65 66 public void visitClassfiles(Collection classfiles) { 67 indent().append("<classfiles>").eol(); 68 raiseIndent(); 69 70 super.visitClassfiles(classfiles); 71 72 lowerIndent(); 73 indent().append("</classfiles>").eol(); 74 } 75 76 public void visitClassfile(Classfile classfile) { 77 Iterator i; 78 79 indent().append("<classfile magic-number=\"").append(classfile.getMagicNumber()).append("\" minor-version=\"").append(classfile.getMinorVersion()).append("\" major-version=\"").append(classfile.getMajorVersion()).append("\" access-flag=\"").append(format.format(classfile.getAccessFlag())).append("\">").eol(); 80 raiseIndent(); 81 82 top = true; 83 classfile.getConstantPool().accept(this); 84 top = false; 85 86 if (classfile.isPublic()) indent().append("<public/>").eol(); 87 if (classfile.isFinal()) indent().append("<final/>").eol(); 88 if (classfile.isSuper()) indent().append("<super/>").eol(); 89 if (classfile.isInterface()) indent().append("<is-interface/>").eol(); 90 if (classfile.isAbstract()) indent().append("<abstract/>").eol(); 91 92 indent(); 93 append("<this-class>"); 94 classfile.getRawClass().accept(this); 95 append("</this-class>").eol(); 96 97 indent(); 98 append("<superclass>"); 99 if (classfile.getSuperclassIndex() != 0) { 100 classfile.getRawSuperclass().accept(this); 101 } 102 append("</superclass>").eol(); 103 104 if (!classfile.getAllInterfaces().isEmpty()) { 105 indent().append("<interfaces>").eol(); 106 raiseIndent(); 107 i = classfile.getAllInterfaces().iterator(); 108 while (i.hasNext()) { 109 indent(); 110 append("<interface>"); 111 ((Visitable) i.next()).accept(this); 112 append("</interface>").eol(); 113 } 114 lowerIndent(); 115 indent().append("</interfaces>").eol(); 116 } 117 118 if (!classfile.getAllFields().isEmpty()) { 119 indent().append("<fields>").eol(); 120 raiseIndent(); 121 i = classfile.getAllFields().iterator(); 122 while (i.hasNext()) { 123 ((Visitable) i.next()).accept(this); 124 } 125 lowerIndent(); 126 indent().append("</fields>").eol(); 127 } 128 129 if (!classfile.getAllMethods().isEmpty()) { 130 indent().append("<methods>").eol(); 131 raiseIndent(); 132 i = classfile.getAllMethods().iterator(); 133 while (i.hasNext()) { 134 ((Visitable) i.next()).accept(this); 135 } 136 lowerIndent(); 137 indent().append("</methods>").eol(); 138 } 139 140 if (!classfile.getAttributes().isEmpty()) { 141 indent().append("<attributes>").eol(); 142 raiseIndent(); 143 i = classfile.getAttributes().iterator(); 144 while (i.hasNext()) { 145 ((Visitable) i.next()).accept(this); 146 } 147 lowerIndent(); 148 indent().append("</attributes>").eol(); 149 } 150 151 lowerIndent(); 152 indent().append("</classfile>").eol(); 153 } 154 155 public void visitConstantPool(ConstantPool constantPool) { 156 resetCount(); 157 158 indent().append("<constant-pool>").eol(); 159 raiseIndent(); 160 161 Iterator i = constantPool.iterator(); 162 while (i.hasNext()) { 163 Visitable entry = (Visitable) i.next(); 164 if (entry != null) { 165 entry.accept(this); 166 } 167 raiseCount(); 168 } 169 170 lowerIndent(); 171 indent().append("</constant-pool>").eol(); 172 } 173 174 public void visitClass_info(Class_info entry) { 175 if (top) { 176 top = false; 177 indent(); 178 append("<class id=\"").append(currentCount()).append("\">"); 179 append(entry.getName()); 181 append("</class>").eol(); 182 top = true; 183 } else { 184 append(entry.getName()); 186 } 187 } 188 189 public void visitFieldRef_info(FieldRef_info entry) { 190 Class_info c = entry.getRawClass(); 191 NameAndType_info nat = entry.getRawNameAndType(); 192 193 if (top) { 194 top = false; 195 indent(); 196 append("<field-ref-info id=\"").append(currentCount()).append("\">"); 197 append("<class>"); 198 c.accept(this); 199 append("</class>"); 200 append("<type>"); 201 nat.getRawType().accept(this); 202 append("</type>"); 203 append("<name>"); 204 nat.getRawName().accept(this); 205 append("</name>"); 206 append("</field-ref-info>").eol(); 207 top = true; 208 } else { 209 append(SignatureHelper.getType(nat.getType())); 210 append(" "); 211 append(entry.getFullSignature()); 212 } 213 } 214 215 public void visitMethodRef_info(MethodRef_info entry) { 216 Class_info c = entry.getRawClass(); 217 NameAndType_info nat = entry.getRawNameAndType(); 218 219 if (top) { 220 top = false; 221 indent(); 222 append("<method-ref-info id=\"").append(currentCount()).append("\">"); 223 append("<class>"); 224 c.accept(this); 225 append("</class>"); 226 append("<name>"); 227 nat.getRawName().accept(this); 228 append("</name>"); 229 append("<type>"); 230 nat.getRawType().accept(this); 231 append("</type>"); 232 append("</method-ref-info>").eol(); 233 top = true; 234 } else { 235 if (!entry.isConstructor() && !entry.isStaticInitializer()) { 236 append(SignatureHelper.getReturnType(nat.getType())).append(" "); 237 } 238 append(entry.getFullSignature()); 239 } 240 } 241 242 public void visitInterfaceMethodRef_info(InterfaceMethodRef_info entry) { 243 Class_info c = entry.getRawClass(); 244 NameAndType_info nat = entry.getRawNameAndType(); 245 246 if (top) { 247 top = false; 248 indent(); 249 append("<interface-method-ref-info id=\"").append(currentCount()).append("\">"); 250 append("<class>"); 251 c.accept(this); 252 append("</class>"); 253 append("<name>"); 254 nat.getRawName().accept(this); 255 append("</name>"); 256 append("<type>"); 257 nat.getRawType().accept(this); 258 append("</type>"); 259 append("</interface-method-ref-info>").eol(); 260 top = true; 261 } else { 262 append(SignatureHelper.getReturnType(nat.getType())); 263 append(" "); 264 append(entry.getFullSignature()); 265 } 266 } 267 268 public void visitString_info(String_info entry) { 269 if (top) { 270 top = false; 271 indent(); 272 append("<string-info id=\"").append(currentCount()).append("\">"); 273 entry.getRawValue().accept(this); 274 append("</string-info>").eol(); 275 top = true; 276 } else { 277 entry.getRawValue().accept(this); 278 } 279 } 280 281 public void visitInteger_info(Integer_info entry) { 282 if (top) { 283 top = false; 284 indent(); 285 append("<integer-info id=\"").append(currentCount()).append("\">"); 286 append(entry.getValue()); 287 append("</integer-info>").eol(); 288 top = true; 289 } else { 290 append(entry.getValue()); 291 } 292 } 293 294 public void visitFloat_info(Float_info entry) { 295 if (top) { 296 top = false; 297 indent(); 298 append("<float-info id=\"").append(currentCount()).append("\">"); 299 append(entry.getValue()); 300 append("</float-info>").eol(); 301 top = true; 302 } else { 303 append(entry.getValue()); 304 } 305 } 306 307 public void visitLong_info(Long_info entry) { 308 if (top) { 309 top = false; 310 indent(); 311 append("<long-info id=\"").append(currentCount()).append("\">"); 312 append(entry.getValue()); 313 append("</long-info>").eol(); 314 top = true; 315 } else { 316 append(entry.getValue()); 317 } 318 } 319 320 public void visitDouble_info(Double_info entry) { 321 if (top) { 322 top = false; 323 indent(); 324 append("<double-info id=\"").append(currentCount()).append("\">"); 325 append(entry.getValue()); 326 append("</double-info>").eol(); 327 top = true; 328 } else { 329 append(entry.getValue()); 330 } 331 } 332 333 public void visitNameAndType_info(NameAndType_info entry) { 334 if (top) { 335 top = false; 336 indent(); 337 append("<name-and-type-info id=\"").append(currentCount()).append("\">"); 338 append("<name>"); 339 entry.getRawName().accept(this); 340 append("</name>"); 341 append("<type>"); 342 entry.getRawType().accept(this); 343 append("</type>"); 344 append("</name-and-type-info>").eol(); 345 top = true; 346 } else { 347 entry.getRawName().accept(this); 348 append(" "); 349 entry.getRawType().accept(this); 350 } 351 } 352 353 public void visitUTF8_info(UTF8_info entry) { 354 if (top) { 355 top = false; 356 indent().append("<utf8-info id=\"").append(currentCount()).append("\">"); 357 append(escapeXMLCharacters(entry.getValue())); 358 append("</utf8-info>").eol(); 359 top = true; 360 } else { 361 append(escapeXMLCharacters(entry.getValue())); 362 } 363 } 364 365 public void visitField_info(Field_info entry) { 366 indent().append("<field-info access-flag=\"").append(format.format(entry.getAccessFlag())).append("\">").eol(); 367 raiseIndent(); 368 369 if (entry.isPublic()) indent().append("<public/>").eol(); 370 if (entry.isProtected()) indent().append("<protected/>").eol(); 371 if (entry.isPrivate()) indent().append("<private/>").eol(); 372 if (entry.isStatic()) indent().append("<static/>").eol(); 373 if (entry.isFinal()) indent().append("<final/>").eol(); 374 if (entry.isVolatile()) indent().append("<volatile/>").eol(); 375 if (entry.isTransient()) indent().append("<transient/>").eol(); 376 377 indent(); 378 append("<name>"); 379 entry.getRawName().accept(this); 380 append("</name>").eol(); 381 382 indent().append("<type>").append(entry.getType()).append("</type>").eol(); 383 384 if (!entry.getAttributes().isEmpty()) { 385 indent().append("<attributes>").eol(); 386 raiseIndent(); 387 super.visitField_info(entry); 388 lowerIndent(); 389 indent().append("</attributes>").eol(); 390 } 391 392 lowerIndent(); 393 indent().append("</field-info>").eol(); 394 } 395 396 public void visitMethod_info(Method_info entry) { 397 indent().append("<method-info access-flag=\"").append(format.format(entry.getAccessFlag())).append("\">").eol(); 398 raiseIndent(); 399 400 if (entry.isPublic()) indent().append("<public/>").eol(); 401 if (entry.isProtected()) indent().append("<protected/>").eol(); 402 if (entry.isPrivate()) indent().append("<private/>").eol(); 403 if (entry.isStatic()) indent().append("<static/>").eol(); 404 if (entry.isFinal()) indent().append("<final/>").eol(); 405 if (entry.isSynchronized()) indent().append("<synchronized/>").eol(); 406 if (entry.isNative()) indent().append("<native/>").eol(); 407 if (entry.isAbstract()) indent().append("<abstract/>").eol(); 408 if (entry.isStrict()) indent().append("<strict/>").eol(); 409 410 indent(); 411 append("<name>"); 412 entry.getRawName().accept(this); 413 append("</name>").eol(); 414 415 if (!entry.getName().equals("<init>") && !entry.getName().equals("<clinit>")) { 416 indent().append("<return-type>").append((entry.getReturnType() != null) ? entry.getReturnType() : "void").append("</return-type>").eol(); 417 } 418 indent().append("<signature>").append(entry.getSignature()).append("</signature>").eol(); 419 420 if (!entry.getAttributes().isEmpty()) { 421 indent().append("<attributes>").eol(); 422 raiseIndent(); 423 super.visitMethod_info(entry); 424 lowerIndent(); 425 indent().append("</attributes>").eol(); 426 } 427 428 lowerIndent(); 429 indent().append("</method-info>").eol(); 430 } 431 432 public void visitConstantValue_attribute(ConstantValue_attribute attribute) { 433 indent().append("<constant-value-attribute>").eol(); 434 raiseIndent(); 435 436 attribute.getRawValue().accept(this); 437 438 lowerIndent(); 439 indent().append("</constant-value-attribute>").eol(); 440 } 441 442 public void visitCode_attribute(Code_attribute attribute) { 443 Iterator i; 444 445 indent().append("<code-attribute>").eol(); 446 raiseIndent(); 447 448 indent().append("<length>").append(attribute.getCode().length).append("</length>").eol(); 449 450 indent().append("<instructions>").eol(); 451 raiseIndent(); 452 i = attribute.iterator(); 453 while (i.hasNext()) { 454 Instruction instr = (Instruction) i.next(); 455 indent(); 456 append("<instruction pc=\"").append(instr.getStart()).append("\" length=\"").append(instr.getLength()).append("\">"); 457 switch (instr.getOpcode()) { 458 case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: case 0xb8: case 0xb9: case 0xbb: case 0xbd: case 0xc0: case 0xc1: case 0xc5: int index = ((instr.getCode()[instr.getStart()+1] & 0xff) << 8) | (instr.getCode()[instr.getStart()+2] & 0xff); 472 append(instr); 473 append(" "); 474 ((ConstantPoolEntry) attribute.getClassfile().getConstantPool().get(index)).accept(this); 475 break; 476 default: 477 append(instr); 478 break; 479 } 480 append("</instruction>").eol(); 481 } 482 lowerIndent(); 483 indent().append("</instructions>").eol(); 484 485 if (!attribute.getExceptionHandlers().isEmpty()) { 486 indent().append("<exception-handlers>").eol(); 487 raiseIndent(); 488 i = attribute.getExceptionHandlers().iterator(); 489 while (i.hasNext()) { 490 ((Visitable) i.next()).accept(this); 491 } 492 lowerIndent(); 493 indent().append("</exception-handlers>").eol(); 494 } 495 496 if (!attribute.getAttributes().isEmpty()) { 497 indent().append("<attributes>").eol(); 498 raiseIndent(); 499 i = attribute.getAttributes().iterator(); 500 while (i.hasNext()) { 501 ((Visitable) i.next()).accept(this); 502 } 503 lowerIndent(); 504 indent().append("</attributes>").eol(); 505 } 506 507 lowerIndent(); 508 indent().append("</code-attribute>").eol(); 509 } 510 511 public void visitExceptions_attribute(Exceptions_attribute attribute) { 512 indent().append("<exceptions-attribute>").eol(); 513 raiseIndent(); 514 515 Iterator i = attribute.getExceptions().iterator(); 516 while (i.hasNext()) { 517 indent(); 518 append("<exception>"); 519 ((Visitable) i.next()).accept(this); 520 append("</exception>").eol(); 521 } 522 523 lowerIndent(); 524 indent().append("</exceptions-attribute>").eol(); 525 } 526 527 public void visitInnerClasses_attribute(InnerClasses_attribute attribute) { 528 indent().append("<inner-classes-attribute>").eol(); 529 raiseIndent(); 530 531 Iterator i = attribute.getClasses().iterator(); 532 while (i.hasNext()) { 533 ((Visitable) i.next()).accept(this); 534 } 535 536 lowerIndent(); 537 indent().append("</inner-classes-attribute>").eol(); 538 } 539 540 public void visitSynthetic_attribute(Synthetic_attribute attribute) { 541 indent().append("<synthetic-attribute/>").eol(); 542 } 543 544 public void visitSourceFile_attribute(SourceFile_attribute attribute) { 545 indent().append("<source-file-attribute>").append(attribute.getSourceFile()).append("</source-file-attribute>").eol(); 546 } 547 548 public void visitLineNumberTable_attribute(LineNumberTable_attribute attribute) { 549 indent().append("<line-number-table-attribute>").eol(); 550 raiseIndent(); 551 552 Iterator i = attribute.getLineNumbers().iterator(); 553 while (i.hasNext()) { 554 ((Visitable) i.next()).accept(this); 555 } 556 557 lowerIndent(); 558 indent().append("</line-number-table-attribute>").eol(); 559 } 560 561 public void visitLocalVariableTable_attribute(LocalVariableTable_attribute attribute) { 562 indent().append("<local-variable-table-attribute>").eol(); 563 raiseIndent(); 564 565 Iterator i = attribute.getLocalVariables().iterator(); 566 while (i.hasNext()) { 567 ((Visitable) i.next()).accept(this); 568 } 569 570 lowerIndent(); 571 indent().append("</local-variable-table-attribute>").eol(); 572 } 573 574 public void visitDeprecated_attribute(Deprecated_attribute attribute) { 575 indent().append("<deprecated-attribute/>").eol(); 576 } 577 578 public void visitExceptionHandler(ExceptionHandler helper) { 579 indent(); 580 append("<exception-handler>"); 581 append("<start-pc>").append(helper.getStartPC()).append("</start-pc>"); 582 append("<end-pc>").append(helper.getEndPC()).append("</end-pc>"); 583 append("<handler-pc>").append(helper.getHandlerPC()).append("</handler-pc>"); 584 585 append("<catch-type>"); 586 if (helper.getCatchTypeIndex() != 0) { 587 helper.getRawCatchType().accept(this); 588 } 589 append("</catch-type>"); 590 591 append("</exception-handler>").eol(); 592 } 593 594 public void visitInnerClass(InnerClass helper) { 595 indent().append("<inner-class access-flag=\"").append(format.format(helper.getAccessFlag())).append("\">").eol(); 596 raiseIndent(); 597 598 if (helper.isPublic()) indent().append("<public/>").eol(); 599 if (helper.isProtected()) indent().append("<protected/>").eol(); 600 if (helper.isPrivate()) indent().append("<private/>").eol(); 601 if (helper.isStatic()) indent().append("<static/>").eol(); 602 if (helper.isFinal()) indent().append("<final/>").eol(); 603 if (helper.isInterface()) indent().append("<is-interface/>").eol(); 604 if (helper.isAbstract()) indent().append("<abstract/>").eol(); 605 606 indent(); 607 append("<inner-class-info>"); 608 if (helper.getInnerClassInfoIndex() != 0) { 609 helper.getRawInnerClassInfo().accept(this); 610 } 611 append("</inner-class-info>").eol(); 612 613 indent(); 614 append("<outer-class-info>"); 615 if (helper.getOuterClassInfoIndex() != 0) { 616 helper.getRawOuterClassInfo().accept(this); 617 } 618 append("</outer-class-info>").eol(); 619 620 indent(); 621 append("<inner-name>"); 622 if (helper.getInnerNameIndex() != 0) { 623 helper.getRawInnerName().accept(this); 624 } 625 append("</inner-name>").eol(); 626 627 lowerIndent(); 628 indent().append("</inner-class>").eol(); 629 } 630 631 public void visitLineNumber(LineNumber helper) { 632 indent(); 633 append("<line-number>"); 634 append("<start-pc>").append(helper.getStartPC()).append("</start-pc>"); 635 append("<line>").append(helper.getLineNumber()).append("</line>"); 636 append("</line-number>").eol(); 637 } 638 639 public void visitLocalVariable(LocalVariable helper) { 640 indent(); 641 append("<local-variable pc=\"").append(helper.getStartPC()).append("\" length=\"").append(helper.getLength()).append("\">"); 642 append("<name>"); 643 helper.getRawName().accept(this); 644 append("</name>"); 645 646 append("<type>").append(SignatureHelper.getType(helper.getDescriptor())).append("</type>"); 647 append("</local-variable>").eol(); 648 } 649 650 private String escapeXMLCharacters(String text) { 651 String result = text; 652 653 result = perl.substitute("s/&/&/g", result); 654 result = perl.substitute("s/</</g", result); 655 result = perl.substitute("s/>/>/g", result); 656 657 return result; 658 } 659 } 660 | Popular Tags |