1 /* 2 * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.tools.javap; 27 28 import java.net.URI; 29 import java.text.DateFormat; 30 import java.util.Collection; 31 import java.util.Date; 32 import java.util.List; 33 34 import com.sun.tools.classfile.AccessFlags; 35 import com.sun.tools.classfile.Attribute; 36 import com.sun.tools.classfile.Attributes; 37 import com.sun.tools.classfile.ClassFile; 38 import com.sun.tools.classfile.Code_attribute; 39 import com.sun.tools.classfile.ConstantPool; 40 import com.sun.tools.classfile.ConstantPoolException; 41 import com.sun.tools.classfile.ConstantValue_attribute; 42 import com.sun.tools.classfile.Descriptor; 43 import com.sun.tools.classfile.Descriptor.InvalidDescriptor; 44 import com.sun.tools.classfile.Exceptions_attribute; 45 import com.sun.tools.classfile.Field; 46 import com.sun.tools.classfile.Method; 47 import com.sun.tools.classfile.Module_attribute; 48 import com.sun.tools.classfile.Signature; 49 import com.sun.tools.classfile.Signature_attribute; 50 import com.sun.tools.classfile.SourceFile_attribute; 51 import com.sun.tools.classfile.Type; 52 import com.sun.tools.classfile.Type.ArrayType; 53 import com.sun.tools.classfile.Type.ClassSigType; 54 import com.sun.tools.classfile.Type.ClassType; 55 import com.sun.tools.classfile.Type.MethodType; 56 import com.sun.tools.classfile.Type.SimpleType; 57 import com.sun.tools.classfile.Type.TypeParamType; 58 import com.sun.tools.classfile.Type.WildcardType; 59 60 import static com.sun.tools.classfile.AccessFlags.*; 61 62 /* 63 * The main javap class to write the contents of a class file as text. 64 * 65 * <p><b>This is NOT part of any supported API. 66 * If you write code that depends on this, you do so at your own risk. 67 * This code and its internal interfaces are subject to change or 68 * deletion without notice.</b> 69 */ 70 public class ClassWriter extends BasicWriter { 71 static ClassWriter instance(Context context) { 72 ClassWriter instance = context.get(ClassWriter.class); 73 if (instance == null) 74 instance = new ClassWriter(context); 75 return instance; 76 } 77 78 protected ClassWriter(Context context) { 79 super(context); 80 context.put(ClassWriter.class, this); 81 options = Options.instance(context); 82 attrWriter = AttributeWriter.instance(context); 83 codeWriter = CodeWriter.instance(context); 84 constantWriter = ConstantWriter.instance(context); 85 } 86 87 void setDigest(String name, byte[] digest) { 88 this.digestName = name; 89 this.digest = digest; 90 } 91 92 void setFile(URI uri) { 93 this.uri = uri; 94 } 95 96 void setFileSize(int size) { 97 this.size = size; 98 } 99 100 void setLastModified(long lastModified) { 101 this.lastModified = lastModified; 102 } 103 104 protected ClassFile getClassFile() { 105 return classFile; 106 } 107 108 protected void setClassFile(ClassFile cf) { 109 classFile = cf; 110 constant_pool = classFile.constant_pool; 111 } 112 113 protected Method getMethod() { 114 return method; 115 } 116 117 protected void setMethod(Method m) { 118 method = m; 119 } 120 121 public void write(ClassFile cf) { 122 setClassFile(cf); 123 124 if (options.sysInfo || options.verbose) { 125 if (uri != null) { 126 if (uri.getScheme().equals("file")) 127 println("Classfile " + uri.getPath()); 128 else 129 println("Classfile " + uri); 130 } 131 indent(+1); 132 if (lastModified != -1) { 133 Date lm = new Date(lastModified); 134 DateFormat df = DateFormat.getDateInstance(); 135 if (size > 0) { 136 println("Last modified " + df.format(lm) + "; size " + size + " bytes"); 137 } else { 138 println("Last modified " + df.format(lm)); 139 } 140 } else if (size > 0) { 141 println("Size " + size + " bytes"); 142 } 143 if (digestName != null && digest != null) { 144 StringBuilder sb = new StringBuilder(); 145 for (byte b: digest) 146 sb.append(String.format("%02x", b)); 147 println(digestName + " checksum " + sb); 148 } 149 } 150 151 Attribute sfa = cf.getAttribute(Attribute.SourceFile); 152 if (sfa instanceof SourceFile_attribute) { 153 println("Compiled from \"" + getSourceFile((SourceFile_attribute) sfa) + "\""); 154 } 155 156 if (options.sysInfo || options.verbose) { 157 indent(-1); 158 } 159 160 AccessFlags flags = cf.access_flags; 161 writeModifiers(flags.getClassModifiers()); 162 163 if (classFile.access_flags.is(AccessFlags.ACC_MODULE)) { 164 Attribute attr = classFile.attributes.get(Attribute.Module); 165 if (attr instanceof Module_attribute) { 166 Module_attribute modAttr = (Module_attribute) attr; 167 String name; 168 try { 169 name = getJavaName(constant_pool.getUTF8Value(modAttr.module_name)); 170 } catch (ConstantPoolException e) { 171 name = report(e); 172 } 173 if ((modAttr.module_flags & Module_attribute.ACC_OPEN) != 0) { 174 print("open "); 175 } 176 print("module "); 177 print(name); 178 } else { 179 // fallback for malformed class files 180 print("class "); 181 print(getJavaName(classFile)); 182 } 183 } else { 184 if (classFile.isClass()) 185 print("class "); 186 else if (classFile.isInterface()) 187 print("interface "); 188 189 print(getJavaName(classFile)); 190 } 191 192 Signature_attribute sigAttr = getSignature(cf.attributes); 193 if (sigAttr == null) { 194 // use info from class file header 195 if (classFile.isClass() && classFile.super_class != 0 ) { 196 String sn = getJavaSuperclassName(cf); 197 if (!sn.equals("java.lang.Object")) { 198 print(" extends "); 199 print(sn); 200 } 201 } 202 for (int i = 0; i < classFile.interfaces.length; i++) { 203 print(i == 0 ? (classFile.isClass() ? " implements " : " extends ") : ","); 204 print(getJavaInterfaceName(classFile, i)); 205 } 206 } else { 207 try { 208 Type t = sigAttr.getParsedSignature().getType(constant_pool); 209 JavaTypePrinter p = new JavaTypePrinter(classFile.isInterface()); 210 // The signature parser cannot disambiguate between a 211 // FieldType and a ClassSignatureType that only contains a superclass type. 212 if (t instanceof Type.ClassSigType) { 213 print(p.print(t)); 214 } else if (options.verbose || !t.isObject()) { 215 print(" extends "); 216 print(p.print(t)); 217 } 218 } catch (ConstantPoolException e) { 219 print(report(e)); 220 } 221 } 222 223 if (options.verbose) { 224 println(); 225 indent(+1); 226 println("minor version: " + cf.minor_version); 227 println("major version: " + cf.major_version); 228 writeList(String.format("flags: (0x%04x) ", flags.flags), flags.getClassFlags(), "\n"); 229 print("this_class: #" + cf.this_class); 230 if (cf.this_class != 0) { 231 tab(); 232 print("// " + constantWriter.stringValue(cf.this_class)); 233 } 234 println(); 235 print("super_class: #" + cf.super_class); 236 if (cf.super_class != 0) { 237 tab(); 238 print("// " + constantWriter.stringValue(cf.super_class)); 239 } 240 println(); 241 print("interfaces: " + cf.interfaces.length); 242 print(", fields: " + cf.fields.length); 243 print(", methods: " + cf.methods.length); 244 println(", attributes: " + cf.attributes.attrs.length); 245 indent(-1); 246 constantWriter.writeConstantPool(); 247 } else { 248 print(" "); 249 } 250 251 println("{"); 252 indent(+1); 253 if (flags.is(AccessFlags.ACC_MODULE) && !options.verbose) { 254 writeDirectives(); 255 } 256 writeFields(); 257 writeMethods(); 258 indent(-1); 259 println("}"); 260 261 if (options.verbose) { 262 attrWriter.write(cf, cf.attributes, constant_pool); 263 } 264 } 265 // where 266 class JavaTypePrinter implements Type.Visitor<StringBuilder,StringBuilder> { 267 boolean isInterface; 268 269 JavaTypePrinter(boolean isInterface) { 270 this.isInterface = isInterface; 271 } 272 273 String print(Type t) { 274 return t.accept(this, new StringBuilder()).toString(); 275 } 276 277 String printTypeArgs(List<? extends TypeParamType> typeParamTypes) { 278 StringBuilder builder = new StringBuilder(); 279 appendIfNotEmpty(builder, "<", typeParamTypes, "> "); 280 return builder.toString(); 281 } 282 283 @Override 284 public StringBuilder visitSimpleType(SimpleType type, StringBuilder sb) { 285 sb.append(getJavaName(type.name)); 286 return sb; 287 } 288 289 @Override 290 public StringBuilder visitArrayType(ArrayType type, StringBuilder sb) { 291 append(sb, type.elemType); 292 sb.append("[]"); 293 return sb; 294 } 295 296 @Override 297 public StringBuilder visitMethodType(MethodType type, StringBuilder sb) { 298 appendIfNotEmpty(sb, "<", type.typeParamTypes, "> "); 299 append(sb, type.returnType); 300 append(sb, " (", type.paramTypes, ")"); 301 appendIfNotEmpty(sb, " throws ", type.throwsTypes, ""); 302 return sb; 303 } 304 305 @Override 306 public StringBuilder visitClassSigType(ClassSigType type, StringBuilder sb) { 307 appendIfNotEmpty(sb, "<", type.typeParamTypes, ">"); 308 if (isInterface) { 309 appendIfNotEmpty(sb, " extends ", type.superinterfaceTypes, ""); 310 } else { 311 if (type.superclassType != null 312 && (options.verbose || !type.superclassType.isObject())) { 313 sb.append(" extends "); 314 append(sb, type.superclassType); 315 } 316 appendIfNotEmpty(sb, " implements ", type.superinterfaceTypes, ""); 317 } 318 return sb; 319 } 320 321 @Override 322 public StringBuilder visitClassType(ClassType type, StringBuilder sb) { 323 if (type.outerType != null) { 324 append(sb, type.outerType); 325 sb.append("."); 326 } 327 sb.append(getJavaName(type.name)); 328 appendIfNotEmpty(sb, "<", type.typeArgs, ">"); 329 return sb; 330 } 331 332 @Override 333 public StringBuilder visitTypeParamType(TypeParamType type, StringBuilder sb) { 334 sb.append(type.name); 335 String sep = " extends "; 336 if (type.classBound != null 337 && (options.verbose || !type.classBound.isObject())) { 338 sb.append(sep); 339 append(sb, type.classBound); 340 sep = " & "; 341 } 342 if (type.interfaceBounds != null) { 343 for (Type bound: type.interfaceBounds) { 344 sb.append(sep); 345 append(sb, bound); 346 sep = " & "; 347 } 348 } 349 return sb; 350 } 351 352 @Override 353 public StringBuilder visitWildcardType(WildcardType type, StringBuilder sb) { 354 switch (type.kind) { 355 case UNBOUNDED: 356 sb.append("?"); 357 break; 358 case EXTENDS: 359 sb.append("? extends "); 360 append(sb, type.boundType); 361 break; 362 case SUPER: 363 sb.append("? super "); 364 append(sb, type.boundType); 365 break; 366 default: 367 throw new AssertionError(); 368 } 369 return sb; 370 } 371 372 private void append(StringBuilder sb, Type t) { 373 t.accept(this, sb); 374 } 375 376 private void append(StringBuilder sb, String prefix, List<? extends Type> list, String suffix) { 377 sb.append(prefix); 378 String sep = ""; 379 for (Type t: list) { 380 sb.append(sep); 381 append(sb, t); 382 sep = ", "; 383 } 384 sb.append(suffix); 385 } 386 387 private void appendIfNotEmpty(StringBuilder sb, String prefix, List<? extends Type> list, String suffix) { 388 if (!isEmpty(list)) 389 append(sb, prefix, list, suffix); 390 } 391 392 private boolean isEmpty(List<? extends Type> list) { 393 return (list == null || list.isEmpty()); 394 } 395 } 396 397 protected void writeFields() { 398 for (Field f: classFile.fields) { 399 writeField(f); 400 } 401 } 402 403 protected void writeField(Field f) { 404 if (!options.checkAccess(f.access_flags)) 405 return; 406 407 AccessFlags flags = f.access_flags; 408 writeModifiers(flags.getFieldModifiers()); 409 Signature_attribute sigAttr = getSignature(f.attributes); 410 if (sigAttr == null) 411 print(getJavaFieldType(f.descriptor)); 412 else { 413 try { 414 Type t = sigAttr.getParsedSignature().getType(constant_pool); 415 print(getJavaName(t.toString())); 416 } catch (ConstantPoolException e) { 417 // report error? 418 // fall back on non-generic descriptor 419 print(getJavaFieldType(f.descriptor)); 420 } 421 } 422 print(" "); 423 print(getFieldName(f)); 424 if (options.showConstants) { 425 Attribute a = f.attributes.get(Attribute.ConstantValue); 426 if (a instanceof ConstantValue_attribute) { 427 print(" = "); 428 ConstantValue_attribute cv = (ConstantValue_attribute) a; 429 print(getConstantValue(f.descriptor, cv.constantvalue_index)); 430 } 431 } 432 print(";"); 433 println(); 434 435 indent(+1); 436 437 boolean showBlank = false; 438 439 if (options.showDescriptors) 440 println("descriptor: " + getValue(f.descriptor)); 441 442 if (options.verbose) 443 writeList(String.format("flags: (0x%04x) ", flags.flags), flags.getFieldFlags(), "\n"); 444 445 if (options.showAllAttrs) { 446 for (Attribute attr: f.attributes) 447 attrWriter.write(f, attr, constant_pool); 448 showBlank = true; 449 } 450 451 indent(-1); 452 453 if (showBlank || options.showDisassembled || options.showLineAndLocalVariableTables) 454 println(); 455 } 456 457 protected void writeMethods() { 458 for (Method m: classFile.methods) 459 writeMethod(m); 460 setPendingNewline(false); 461 } 462 463 protected void writeMethod(Method m) { 464 if (!options.checkAccess(m.access_flags)) 465 return; 466 467 method = m; 468 469 AccessFlags flags = m.access_flags; 470 471 Descriptor d; 472 Type.MethodType methodType; 473 List<? extends Type> methodExceptions; 474 475 Signature_attribute sigAttr = getSignature(m.attributes); 476 if (sigAttr == null) { 477 d = m.descriptor; 478 methodType = null; 479 methodExceptions = null; 480 } else { 481 Signature methodSig = sigAttr.getParsedSignature(); 482 d = methodSig; 483 try { 484 methodType = (Type.MethodType) methodSig.getType(constant_pool); 485 methodExceptions = methodType.throwsTypes; 486 if (methodExceptions != null && methodExceptions.isEmpty()) 487 methodExceptions = null; 488 } catch (ConstantPoolException e) { 489 // report error? 490 // fall back on standard descriptor 491 methodType = null; 492 methodExceptions = null; 493 } 494 } 495 496 writeModifiers(flags.getMethodModifiers()); 497 if (methodType != null) { 498 print(new JavaTypePrinter(false).printTypeArgs(methodType.typeParamTypes)); 499 } 500 switch (getName(m)) { 501 case "<init>": 502 print(getJavaName(classFile)); 503 print(getJavaParameterTypes(d, flags)); 504 break; 505 case "<clinit>": 506 print("{}"); 507 break; 508 default: 509 print(getJavaReturnType(d)); 510 print(" "); 511 print(getName(m)); 512 print(getJavaParameterTypes(d, flags)); 513 break; 514 } 515 516 Attribute e_attr = m.attributes.get(Attribute.Exceptions); 517 if (e_attr != null) { // if there are generic exceptions, there must be erased exceptions 518 if (e_attr instanceof Exceptions_attribute) { 519 Exceptions_attribute exceptions = (Exceptions_attribute) e_attr; 520 print(" throws "); 521 if (methodExceptions != null) { // use generic list if available 522 writeList("", methodExceptions, ""); 523 } else { 524 for (int i = 0; i < exceptions.number_of_exceptions; i++) { 525 if (i > 0) 526 print(", "); 527 print(getJavaException(exceptions, i)); 528 } 529 } 530 } else { 531 report("Unexpected or invalid value for Exceptions attribute"); 532 } 533 } 534 535 println(";"); 536 537 indent(+1); 538 539 if (options.showDescriptors) { 540 println("descriptor: " + getValue(m.descriptor)); 541 } 542 543 if (options.verbose) { 544 writeList(String.format("flags: (0x%04x) ", flags.flags), flags.getMethodFlags(), "\n"); 545 } 546 547 Code_attribute code = null; 548 Attribute c_attr = m.attributes.get(Attribute.Code); 549 if (c_attr != null) { 550 if (c_attr instanceof Code_attribute) 551 code = (Code_attribute) c_attr; 552 else 553 report("Unexpected or invalid value for Code attribute"); 554 } 555 556 if (options.showAllAttrs) { 557 Attribute[] attrs = m.attributes.attrs; 558 for (Attribute attr: attrs) 559 attrWriter.write(m, attr, constant_pool); 560 } else if (code != null) { 561 if (options.showDisassembled) { 562 println("Code:"); 563 codeWriter.writeInstrs(code); 564 codeWriter.writeExceptionTable(code); 565 } 566 567 if (options.showLineAndLocalVariableTables) { 568 attrWriter.write(code, code.attributes.get(Attribute.LineNumberTable), constant_pool); 569 attrWriter.write(code, code.attributes.get(Attribute.LocalVariableTable), constant_pool); 570 } 571 } 572 573 indent(-1); 574 575 // set pendingNewline to write a newline before the next method (if any) 576 // if a separator is desired 577 setPendingNewline( 578 options.showDisassembled || 579 options.showAllAttrs || 580 options.showDescriptors || 581 options.showLineAndLocalVariableTables || 582 options.verbose); 583 } 584 585 void writeModifiers(Collection<String> items) { 586 for (Object item: items) { 587 print(item); 588 print(" "); 589 } 590 } 591 592 void writeDirectives() { 593 Attribute attr = classFile.attributes.get(Attribute.Module); 594 if (!(attr instanceof Module_attribute)) 595 return; 596 597 Module_attribute m = (Module_attribute) attr; 598 for (Module_attribute.RequiresEntry entry: m.requires) { 599 print("requires"); 600 if ((entry.requires_flags & Module_attribute.ACC_STATIC_PHASE) != 0) 601 print(" static"); 602 if ((entry.requires_flags & Module_attribute.ACC_TRANSITIVE) != 0) 603 print(" transitive"); 604 print(" "); 605 print(getUTF8Value(entry.requires_index).replace('/', '.')); 606 println(";"); 607 } 608 609 for (Module_attribute.ExportsEntry entry: m.exports) { 610 print("exports"); 611 print(" "); 612 print(getUTF8Value(entry.exports_index).replace('/', '.')); 613 boolean first = true; 614 for (int i: entry.exports_to_index) { 615 String mname; 616 try { 617 mname = classFile.constant_pool.getUTF8Value(i).replace('/', '.'); 618 } catch (ConstantPoolException e) { 619 mname = report(e); 620 } 621 if (first) { 622 println(" to"); 623 indent(+1); 624 first = false; 625 } else { 626 println(","); 627 } 628 print(mname); 629 } 630 println(";"); 631 if (!first) 632 indent(-1); 633 } 634 635 for (Module_attribute.OpensEntry entry: m.opens) { 636 print("opens"); 637 print(" "); 638 print(getUTF8Value(entry.opens_index).replace('/', '.')); 639 boolean first = true; 640 for (int i: entry.opens_to_index) { 641 String mname; 642 try { 643 mname = classFile.constant_pool.getUTF8Value(i).replace('/', '.'); 644 } catch (ConstantPoolException e) { 645 mname = report(e); 646 } 647 if (first) { 648 println(" to"); 649 indent(+1); 650 first = false; 651 } else { 652 println(","); 653 } 654 print(mname); 655 } 656 println(";"); 657 if (!first) 658 indent(-1); 659 } 660 661 for (int entry: m.uses_index) { 662 print("uses "); 663 print(getClassName(entry).replace('/', '.')); 664 println(";"); 665 } 666 667 for (Module_attribute.ProvidesEntry entry: m.provides) { 668 print("provides "); 669 print(getClassName(entry.provides_index).replace('/', '.')); 670 boolean first = true; 671 for (int i: entry.with_index) { 672 if (first) { 673 println(" with"); 674 indent(+1); 675 first = false; 676 } else { 677 println(","); 678 } 679 print(getClassName(i).replace('/', '.')); 680 } 681 println(";"); 682 if (!first) 683 indent(-1); 684 } 685 } 686 687 String getUTF8Value(int index) { 688 try { 689 return classFile.constant_pool.getUTF8Value(index); 690 } catch (ConstantPoolException e) { 691 return report(e); 692 } 693 } 694 695 String getClassName(int index) { 696 try { 697 return classFile.constant_pool.getClassInfo(index).getName(); 698 } catch (ConstantPoolException e) { 699 return report(e); 700 } 701 } 702 703 void writeList(String prefix, Collection<?> items, String suffix) { 704 print(prefix); 705 String sep = ""; 706 for (Object item: items) { 707 print(sep); 708 print(item); 709 sep = ", "; 710 } 711 print(suffix); 712 } 713 714 void writeListIfNotEmpty(String prefix, List<?> items, String suffix) { 715 if (items != null && items.size() > 0) 716 writeList(prefix, items, suffix); 717 } 718 719 Signature_attribute getSignature(Attributes attributes) { 720 return (Signature_attribute) attributes.get(Attribute.Signature); 721 } 722 723 String adjustVarargs(AccessFlags flags, String params) { 724 if (flags.is(ACC_VARARGS)) { 725 int i = params.lastIndexOf("[]"); 726 if (i > 0) 727 return params.substring(0, i) + "..." + params.substring(i+2); 728 } 729 730 return params; 731 } 732 733 String getJavaName(ClassFile cf) { 734 try { 735 return getJavaName(cf.getName()); 736 } catch (ConstantPoolException e) { 737 return report(e); 738 } 739 } 740 741 String getJavaSuperclassName(ClassFile cf) { 742 try { 743 return getJavaName(cf.getSuperclassName()); 744 } catch (ConstantPoolException e) { 745 return report(e); 746 } 747 } 748 749 String getJavaInterfaceName(ClassFile cf, int index) { 750 try { 751 return getJavaName(cf.getInterfaceName(index)); 752 } catch (ConstantPoolException e) { 753 return report(e); 754 } 755 } 756 757 String getJavaFieldType(Descriptor d) { 758 try { 759 return getJavaName(d.getFieldType(constant_pool)); 760 } catch (ConstantPoolException e) { 761 return report(e); 762 } catch (InvalidDescriptor e) { 763 return report(e); 764 } 765 } 766 767 String getJavaReturnType(Descriptor d) { 768 try { 769 return getJavaName(d.getReturnType(constant_pool)); 770 } catch (ConstantPoolException e) { 771 return report(e); 772 } catch (InvalidDescriptor e) { 773 return report(e); 774 } 775 } 776 777 String getJavaParameterTypes(Descriptor d, AccessFlags flags) { 778 try { 779 return getJavaName(adjustVarargs(flags, d.getParameterTypes(constant_pool))); 780 } catch (ConstantPoolException e) { 781 return report(e); 782 } catch (InvalidDescriptor e) { 783 return report(e); 784 } 785 } 786 787 String getJavaException(Exceptions_attribute attr, int index) { 788 try { 789 return getJavaName(attr.getException(index, constant_pool)); 790 } catch (ConstantPoolException e) { 791 return report(e); 792 } 793 } 794 795 String getValue(Descriptor d) { 796 try { 797 return d.getValue(constant_pool); 798 } catch (ConstantPoolException e) { 799 return report(e); 800 } 801 } 802 803 String getFieldName(Field f) { 804 try { 805 return f.getName(constant_pool); 806 } catch (ConstantPoolException e) { 807 return report(e); 808 } 809 } 810 811 String getName(Method m) { 812 try { 813 return m.getName(constant_pool); 814 } catch (ConstantPoolException e) { 815 return report(e); 816 } 817 } 818 819 static String getJavaName(String name) { 820 return name.replace('/', '.'); 821 } 822 823 String getSourceFile(SourceFile_attribute attr) { 824 try { 825 return attr.getSourceFile(constant_pool); 826 } catch (ConstantPoolException e) { 827 return report(e); 828 } 829 } 830 831 /** 832 * Get the value of an entry in the constant pool as a Java constant. 833 * Characters and booleans are represented by CONSTANT_Intgere entries. 834 * Character and string values are processed to escape characters outside 835 * the basic printable ASCII set. 836 * @param d the descriptor, giving the expected type of the constant 837 * @param index the index of the value in the constant pool 838 * @return a printable string containing the value of the constant. 839 */ 840 String getConstantValue(Descriptor d, int index) { 841 try { 842 ConstantPool.CPInfo cpInfo = constant_pool.get(index); 843 844 switch (cpInfo.getTag()) { 845 case ConstantPool.CONSTANT_Integer: { 846 ConstantPool.CONSTANT_Integer_info info = 847 (ConstantPool.CONSTANT_Integer_info) cpInfo; 848 String t = d.getValue(constant_pool); 849 switch (t) { 850 case "C": 851 // character 852 return getConstantCharValue((char) info.value); 853 case "Z": 854 // boolean 855 return String.valueOf(info.value == 1); 856 default: 857 // other: assume integer 858 return String.valueOf(info.value); 859 } 860 } 861 862 case ConstantPool.CONSTANT_String: { 863 ConstantPool.CONSTANT_String_info info = 864 (ConstantPool.CONSTANT_String_info) cpInfo; 865 return getConstantStringValue(info.getString()); 866 } 867 868 default: 869 return constantWriter.stringValue(cpInfo); 870 } 871 } catch (ConstantPoolException e) { 872 return "#" + index; 873 } 874 } 875 876 private String getConstantCharValue(char c) { 877 StringBuilder sb = new StringBuilder(); 878 sb.append('\''); 879 sb.append(esc(c, '\'')); 880 sb.append('\''); 881 return sb.toString(); 882 } 883 884 private String getConstantStringValue(String s) { 885 StringBuilder sb = new StringBuilder(); 886 sb.append("\""); 887 for (int i = 0; i < s.length(); i++) { 888 sb.append(esc(s.charAt(i), '"')); 889 } 890 sb.append("\""); 891 return sb.toString(); 892 } 893 894 private String esc(char c, char quote) { 895 if (32 <= c && c <= 126 && c != quote && c != '\\') 896 return String.valueOf(c); 897 else switch (c) { 898 case '\b': return "\\b"; 899 case '\n': return "\\n"; 900 case '\t': return "\\t"; 901 case '\f': return "\\f"; 902 case '\r': return "\\r"; 903 case '\\': return "\\\\"; 904 case '\'': return "\\'"; 905 case '\"': return "\\\""; 906 default: return String.format("\\u%04x", (int) c); 907 } 908 } 909 910 private final Options options; 911 private final AttributeWriter attrWriter; 912 private final CodeWriter codeWriter; 913 private final ConstantWriter constantWriter; 914 private ClassFile classFile; 915 private URI uri; 916 private long lastModified; 917 private String digestName; 918 private byte[] digest; 919 private int size; 920 private ConstantPool constant_pool; 921 private Method method; 922 }