001 package sysModel.classFile; 002 003 import sysModel.classFile.attributes.AAttributeInfo; 004 import sysModel.classFile.attributes.SourceFileAttributeInfo; 005 import sysModel.classFile.constantPool.*; 006 import sysModel.classFile.constantPool.visitors.*; 007 008 import java.io.*; 009 import java.util.ArrayList; 010 011 /** 012 * Represents a Java class file. 013 * 014 * @author Mathias Ricken 015 */ 016 public class ClassFile { 017 /** 018 * Major version. 019 */ 020 private short _majorVersion; 021 022 /** 023 * Minor version. 024 */ 025 private short _minorVersion; 026 027 /** 028 * Constant pool. 029 */ 030 private ConstantPool _constantPool = new ConstantPool(); 031 032 /** 033 * Class access flags. 034 */ 035 private short _classAccessFlags; 036 037 /** 038 * Class information about this class. 039 */ 040 private ClassPoolInfo _thisClass; 041 042 /** 043 * Class information about the superclass. 044 */ 045 private ClassPoolInfo _superClass; 046 047 /** 048 * Class information about implemented interfaces. 049 */ 050 private ArrayList<ClassPoolInfo> _interfaces = new ArrayList<ClassPoolInfo>(); 051 052 /** 053 * Fields in the class. 054 */ 055 private ArrayList<FieldInfo> _fields = new ArrayList<FieldInfo>(); 056 057 /** 058 * Methods in the class. 059 */ 060 private ArrayList<MethodInfo> _methods = new ArrayList<MethodInfo>(); 061 062 /** 063 * Attributes of the class. 064 */ 065 private ArrayList<AAttributeInfo> _attributes = new ArrayList<AAttributeInfo>(); 066 067 // Access flags 068 // TODO: Separate class and method access flags? 069 public static final int ACC_PUBLIC = 0x1; 070 public static final int ACC_PRIVATE = 0x2; 071 public static final int ACC_PROTECTED = 0x4; 072 public static final int ACC_STATIC = 0x8; 073 public static final int ACC_FINAL = 0x10; 074 public static final int ACC_SYNCHRONIZED = 0x20; 075 public static final int ACC_VOLATILE = 0x40; 076 public static final int ACC_BRIDGE = 0x40; // for methods 077 public static final int ACC_TRANSIENT = 0x80; 078 public static final int ACC_VARARGS = 0x80; // for methods 079 public static final int ACC_NATIVE = 0x100; 080 public static final int ACC_INTERFACE = 0x200; 081 public static final int ACC_ABSTRACT = 0x400; 082 public static final int ACC_STRICT = 0x800; 083 public static final int ACC_SYNTHETIC = 0x1000; 084 public static final int ACC_ANNOTATION = 0x2000; 085 public static final int ACC_ENUM = 0x4000; 086 087 /** 088 * Java file magic, 0xCAFEBABE. 089 */ 090 private static final int JAVA_FILE_MAGIC = 0xCAFEBABE; 091 092 /** 093 * Create a new ClassFile instance. 094 * @param majorVersion major class file version 095 * @param minorVersion minor class file version 096 * @param classAccessFlags class access flags 097 * @param thisClassName class name 098 * @param superClassName superclass name 099 */ 100 public ClassFile(short majorVersion, 101 short minorVersion, 102 short classAccessFlags, 103 String thisClassName, 104 String superClassName) { 105 _majorVersion = majorVersion; 106 _minorVersion = minorVersion; 107 108 _constantPool = new ConstantPool(1); 109 _constantPool.add(EmptyPoolInfo.singleton()); 110 111 // Resolve and check constant pool 112 for(APoolInfo cpi : _constantPool) { 113 cpi.resolve(); 114 } 115 116 _classAccessFlags = classAccessFlags; 117 118 // add a new name 119 AUTFPoolInfo thisClassNameInfo = new ASCIIPoolInfo(thisClassName, _constantPool); 120 short[] l = addConstantPoolItems(new APoolInfo[]{thisClassNameInfo}); 121 thisClassNameInfo = getConstantPoolItem(l[0]).execute(CheckUTFVisitor.singleton(), null); 122 123 // add a new class 124 _thisClass = new ClassPoolInfo(thisClassNameInfo, _constantPool); 125 l = addConstantPoolItems(new APoolInfo[]{_thisClass}); 126 _thisClass = getConstantPoolItem(l[0]).execute(CheckClassVisitor.singleton(), null); 127 128 if (!"java/lang/Object".equals(thisClassName)) { 129 // add a new name 130 AUTFPoolInfo superClassNameInfo = new ASCIIPoolInfo(superClassName, _constantPool); 131 l = addConstantPoolItems(new APoolInfo[]{superClassNameInfo}); 132 superClassNameInfo = getConstantPoolItem(l[0]).execute(CheckUTFVisitor.singleton(), null); 133 134 // add a new class 135 _superClass = new ClassPoolInfo(superClassNameInfo, _constantPool); 136 l = addConstantPoolItems(new APoolInfo[]{_superClass}); 137 _superClass = getConstantPoolItem(l[0]).execute(CheckClassVisitor.singleton(), null); 138 } 139 140 _interfaces = new ArrayList<ClassPoolInfo>(0); 141 _fields = new ArrayList<FieldInfo>(0); 142 _methods = new ArrayList<MethodInfo>(0); 143 _attributes = new ArrayList<AAttributeInfo>(0); 144 } 145 146 /** 147 * Constructor. 148 * 149 * @param in input stream with class file 150 * 151 * @throws IOException 152 * @throws ClassFormatError 153 */ 154 public ClassFile(InputStream in) throws IOException, ClassFormatError { 155 DataInputStream di = new DataInputStream(in); 156 157 readHeader(di); 158 readConstantPool(di); 159 160 readClassInfo(di); 161 162 readInterfaces(di); 163 readFields(di); 164 readMethods(di); 165 readAttributes(di); 166 } 167 168 /** 169 * Constructor. 170 * 171 * @param b byte array 172 * 173 * @throws IOException 174 * @throws ClassFormatError 175 */ 176 public ClassFile(byte[] b) throws IOException, ClassFormatError { 177 this(new ByteArrayInputStream(b)); 178 } 179 180 /** 181 * Read a class file header. 182 * 183 * @param di stream 184 * 185 * @throws IOException 186 * @throws ClassFormatError 187 */ 188 protected void readHeader(DataInputStream di) throws IOException, ClassFormatError { 189 int magic = di.readInt(); 190 if (JAVA_FILE_MAGIC != magic) { 191 throw new ClassFormatError("Wrong _magic"); 192 } 193 194 _majorVersion = di.readShort(); 195 _minorVersion = di.readShort(); 196 } 197 198 /** 199 * Read constant pool. 200 * 201 * @param di stream 202 * 203 * @throws IOException 204 * @throws ClassFormatError 205 */ 206 protected void readConstantPool(DataInputStream di) throws IOException, ClassFormatError { 207 int count = di.readShort(); 208 209 _constantPool = new ConstantPool(count); 210 for(int i = 0; i < count; ++i) { 211 _constantPool.add(EmptyPoolInfo.singleton()); 212 } 213 214 int index = 1; 215 while(index < _constantPool.size()) { 216 APoolInfo cpi = APoolInfo.read(di, _constantPool); 217 _constantPool.set(index, cpi); 218 index += cpi.execute(GetPoolInfoSizeVisitor.singleton(), null); 219 } 220 221 // Resolve and check constant pool 222 for(APoolInfo cpi : _constantPool) { 223 cpi.resolve(); 224 } 225 } 226 227 /** 228 * Read class information. 229 * 230 * @param di stream 231 * 232 * @throws IOException 233 * @throws ClassFormatError 234 */ 235 protected void readClassInfo(DataInputStream di) throws IOException, ClassFormatError { 236 _classAccessFlags = di.readShort(); 237 238 _thisClass = _constantPool.get(di.readShort()).execute(CheckClassVisitor.singleton(), null); 239 short superClassIndex = di.readShort(); 240 if ("java/lang/Object".equals(_thisClass.getName().toString())) { 241 if (0 != superClassIndex) { 242 throw new ClassFormatError("java.lang.Object must have 0 as superclass index"); 243 } 244 } 245 else { 246 _superClass = _constantPool.get(superClassIndex).execute(CheckClassVisitor.singleton(), null); 247 } 248 } 249 250 /** 251 * Read class file interfaces. 252 * 253 * @param di stream 254 * 255 * @throws IOException 256 * @throws ClassFormatError 257 */ 258 protected void readInterfaces(DataInputStream di) throws IOException, ClassFormatError { 259 int count = di.readShort(); 260 if (0 != count) { 261 _interfaces = new ArrayList<ClassPoolInfo>(count); 262 for(int i = 0; i < count; ++i) { 263 _interfaces.add(null); 264 } 265 266 for(int i = 0; i < count; ++i) { 267 int iindex = di.readShort(); 268 if ((1 > iindex) || (iindex > _constantPool.size() - 1)) { 269 throw new ClassFormatError("Interface number out of range, index=" + i); 270 } 271 _interfaces.set(i, _constantPool.get(iindex).execute(CheckClassVisitor.singleton(), null)); 272 } 273 } 274 } 275 276 /** 277 * Read class file fields. 278 * 279 * @param di stream 280 * 281 * @throws IOException 282 * @throws ClassFormatError 283 */ 284 protected void readFields(DataInputStream di) throws IOException, ClassFormatError { 285 int count = di.readShort(); 286 if (0 != count) { 287 _fields = new ArrayList<FieldInfo>(count); 288 for(int i = 0; i < count; ++i) { 289 _fields.add(null); 290 } 291 for(int i = 0; i < count; ++i) { 292 _fields.set(i, new FieldInfo(di, _constantPool)); 293 } 294 } 295 } 296 297 /** 298 * Read class file methods. 299 * 300 * @param di stream 301 * 302 * @throws IOException 303 * @throws ClassFormatError 304 */ 305 protected void readMethods(DataInputStream di) throws IOException, ClassFormatError { 306 int count = di.readShort(); 307 if (0 != count) { 308 _methods = new ArrayList<MethodInfo>(count); 309 for(int i = 0; i < count; ++i) { 310 _methods.add(null); 311 } 312 for(int i = 0; i < count; ++i) { 313 _methods.set(i, new MethodInfo(di, _constantPool)); 314 } 315 } 316 } 317 318 /** 319 * Read class file attributes. 320 * 321 * @param di stream 322 * 323 * @throws IOException 324 * @throws ClassFormatError 325 */ 326 protected void readAttributes(DataInputStream di) throws IOException, ClassFormatError { 327 int count = di.readShort(); 328 if (0 != count) { 329 _attributes = new ArrayList<AAttributeInfo>(count); 330 for(int i = 0; i < count; ++i) { 331 _attributes.add(null); 332 } 333 for(int i = 0; i < count; ++i) { 334 _attributes.set(i, AAttributeInfo.read(di, _constantPool)); 335 } 336 } 337 } 338 339 /** 340 * Write class file into stream. 341 * 342 * @param out stream 343 * 344 * @throws IOException 345 */ 346 public void write(OutputStream out) throws IOException { 347 DataOutputStream dos = new DataOutputStream(out); 348 349 dos.writeInt(JAVA_FILE_MAGIC); 350 dos.writeShort(_majorVersion); 351 dos.writeShort(_minorVersion); 352 353 dos.writeShort(_constantPool.size()); 354 for(APoolInfo cpi : _constantPool) { 355 if (null != cpi) { 356 cpi.write(dos); 357 } 358 } 359 360 dos.writeShort(_classAccessFlags); 361 dos.writeShort(_constantPool.indexOf(_thisClass)); 362 if ("java/lang/Object".equals(_thisClass.getName().toString())) { 363 dos.writeShort(0); 364 } 365 else { 366 dos.writeShort(_constantPool.indexOf(_superClass)); 367 } 368 369 dos.writeShort(_interfaces.size()); 370 for(ClassPoolInfo intrf : _interfaces) { 371 dos.writeShort(_constantPool.indexOf(intrf)); 372 } 373 374 dos.writeShort(_fields.size()); 375 for(FieldInfo field : _fields) { 376 field.write(dos, _constantPool); 377 } 378 379 dos.writeShort(_methods.size()); 380 for(MethodInfo method : _methods) { 381 method.write(dos, _constantPool); 382 } 383 384 dos.writeShort(_attributes.size()); 385 for(AAttributeInfo attr : _attributes) { 386 attr.write(dos); 387 } 388 } 389 390 /** 391 * Return the name of this class. 392 * 393 * @return name of this class 394 */ 395 public String getThisClassName() { 396 return ClassFileTools.getClassName(_thisClass.getName().toString()); 397 } 398 399 /** 400 * Return the name of the super class or the empty string, if this class is java.lang.Object. 401 * 402 * @return name of super class 403 */ 404 public String getSuperClassName() { 405 if (null != _superClass) { 406 return ClassFileTools.getClassName(_superClass.getName().toString()); 407 } 408 else { 409 return ""; 410 } 411 } 412 413 /** 414 * Return a human-readable version of this class. 415 * 416 * @return string 417 */ 418 public String toString() { 419 return "Class File (Version " + _majorVersion + '.' + _minorVersion + ") for class " + _thisClass.getName(); 420 } 421 422 423 /** 424 * Return a verbose human-readable version of this class. 425 * 426 * @return verbose string 427 */ 428 public String toStringVerbose() { 429 return toStringVerbose(true, true); 430 } 431 432 /** 433 * Return a verbose human-readable version of this class. 434 * 435 * @param lineNumbers print line numbers 436 * @param PCs print PC values 437 * @return verbose string 438 */ 439 public String toStringVerbose(boolean lineNumbers, boolean PCs) { 440 StringWriter sw = new StringWriter(); 441 PrintWriter pw = new PrintWriter(sw); 442 443 // class declaration 444 String thisClassName = getThisClassName(); 445 String superClassName = getSuperClassName(); 446 String packageName = null; 447 448 if (0 < thisClassName.indexOf('.')) { 449 packageName = thisClassName.substring(0, thisClassName.lastIndexOf('.')); 450 thisClassName = thisClassName.substring(thisClassName.lastIndexOf('.') + 1); 451 pw.println("\npackage " + packageName); 452 } 453 454 pw.print( 455 ClassFileTools.getAccessString(_classAccessFlags) + "class " + thisClassName + (!"".equals(superClassName) ? (" extends " + superClassName) : "")); 456 if (0 != _interfaces.size()) { 457 pw.print(" implements "); 458 for(ClassPoolInfo intrf : _interfaces) { 459 pw.print(ClassFileTools.getClassName(intrf.getName().toString()) + ", "); 460 } 461 pw.print(ClassFileTools.getClassName(_interfaces.get(_interfaces.size() - 1).getName().toString())); 462 } 463 464 // print constant pool 465 pw.println("\n\nConstant Pool: " + _constantPool.size() + " items"); 466 int i = 0; 467 for(APoolInfo cpi : _constantPool) { 468 pw.println('#' + String.format("%5d", new Object[]{i++}) + ": " + cpi); 469 } 470 471 // final Set<String> classesUsed = ClassFileTools.getClassNamesUsed(this); 472 // pw.print("\nUsed Classes: " + classesUsed.size() + '\n'); 473 // for(String s: classesUsed) { 474 // pw.println(s); 475 // } 476 477 pw.println("\nAttributes: " + _attributes.size()); 478 i = 0; 479 for(final AAttributeInfo attr : _attributes) { 480 pw.println(" Attribute " + (i++ + 1) + ": " + attr); 481 } 482 483 pw.println("\nFields: " + _fields.size()); 484 for(FieldInfo field : _fields) { 485 pw.println(" " + field.toString(_constantPool)); 486 } 487 488 pw.println("\nMethods: " + _methods.size()); 489 for(MethodInfo method : _methods) { 490 pw.println(" " + method.toString(_constantPool, lineNumbers, PCs)); 491 } 492 493 pw.println(); 494 495 return sw.toString(); 496 } 497 498 /** 499 * Return a constant pool item from this class. This reindexes the constant pool item to make sure the indices are 500 * still correct. 501 * 502 * @param index index of the item 503 * 504 * @return pool item, or null if out of range 505 */ 506 public APoolInfo getConstantPoolItem(short index) { 507 APoolInfo cp; 508 509 if ((0 >= index) || (index > (_constantPool.size() - 1))) { 510 return null; 511 } 512 cp = _constantPool.get(index); 513 cp.reindex(); 514 return cp; 515 } 516 517 /** 518 * Add new items to the constant pool. The items must have been resolved already. The list is pruned to avoid adding 519 * items to the pool that are already there. 520 * <p/> 521 * The function first goes through the list and identifies all those value items (int, long, float, double, ASCII, 522 * and Unicode) that are already in the pool. If an item is already in the pool, it is not added again. Furthermore, 523 * if an item is an ASCII or Unicode UTF item, then all the references to that item present in the list of new items 524 * are changed to point to the item in pool. This is only done for ASCII and Unicode UTF items since they are the 525 * only ones referenced from other items. 526 * <p/> 527 * This process is repeated for all reference items (class, field, method, interface method, name-and-type, and 528 * string) in the list. Here, only name-and-type and class are referenced from other items, so references to them 529 * are changed to point to the pool if they are already in the pool. 530 * <p/> 531 * Finally, items not yet in the pool are added. 532 * 533 * @param items array of new items 534 * 535 * @return array with indices of added items 536 */ 537 public short[] addConstantPoolItems(final APoolInfo[] items) { 538 final short[] indices = new short[items.length]; 539 540 // process value items 541 for(int jv = 0; jv < items.length; ++jv) { 542 final int j = jv; 543 items[j].execute(new AValueReferencePoolInfoVisitor<Object, Object>() { 544 public Object refCase(APoolInfo host, Object o) { 545 // do nothing, not interested in reference objects right now 546 return null; 547 } 548 549 public Object emptyCase(EmptyPoolInfo host, Object o) { 550 // do nothing 551 return null; 552 } 553 554 public Object valueCase(APoolInfo host, Object o) { 555 // check if this object is already in the pool 556 indices[j] = 0; 557 APoolInfo newArg = host.inPool(_constantPool); 558 if (null != newArg) { 559 // yes, mark for deletion 560 indices[j] = _constantPool.indexOf(newArg); 561 } 562 563 return null; 564 } 565 566 public Object asciizCase(ASCIIPoolInfo host, Object o) { 567 return utfCase(host, o); 568 } 569 570 public Object unicodeCase(UnicodePoolInfo host, Object o) { 571 return utfCase(host, o); 572 } 573 574 private Object utfCase(AUTFPoolInfo utfHost, Object o) { 575 // check if this object is already in the pool 576 indices[j] = 0; 577 final AUTFPoolInfo newArg = (AUTFPoolInfo)utfHost.inPool(_constantPool); 578 if (null != newArg) { 579 // yes, mark for deletion 580 indices[j] = _constantPool.indexOf(newArg); 581 582 // update references 583 for(APoolInfo cpi : items) { 584 cpi.execute(new AValueReferencePoolInfoVisitor<Object, Object>() { 585 public Object refCase(APoolInfo host, Object o) { 586 // do nothing, these objects don't have UTF references 587 return null; 588 } 589 590 public Object emptyCase(EmptyPoolInfo host, Object o) { 591 // do nothing 592 return null; 593 } 594 595 public Object valueCase(APoolInfo host, Object o) { 596 // do nothing, value objects don't have references 597 return null; 598 } 599 600 public Object classCase(ClassPoolInfo host, Object o) { 601 // class objects have a UTF reference 602 if (host.getName() == newArg) { 603 // this is affected, update it 604 host.setName(newArg); 605 } 606 return null; 607 } 608 609 public Object stringCase(StringPoolInfo host, Object o) { 610 // string objects have a UTF reference 611 if (host.getUtf() == newArg) { 612 // this is affected, update it 613 host.setUtf(newArg); 614 } 615 return null; 616 } 617 618 public Object nameAndTypeCase(NameAndTypePoolInfo host, Object o) { 619 // name and type objects have two UTF references 620 if (host.getName() == newArg) { 621 // this is affected, update it 622 host.setName(newArg); 623 } 624 if (host.getDescriptor() == newArg) { 625 // this is affected, update it 626 host.setDescriptor(newArg); 627 } 628 return null; 629 } 630 }, null); 631 } 632 } 633 634 return null; 635 } 636 }, null); 637 } 638 639 // process reference items 640 for(int jv = 0; jv < items.length; ++jv) { 641 final int j = jv; 642 items[j].execute(new AValueReferencePoolInfoVisitor<Object, Object>() { 643 public Object valueCase(APoolInfo host, Object o) { 644 // do nothing, not interested in reference objects right now 645 return null; 646 } 647 648 public Object emptyCase(EmptyPoolInfo host, Object o) { 649 // do nothing 650 return null; 651 } 652 653 public Object refCase(APoolInfo host, Object o) { 654 // check if this object is already in the pool 655 indices[j] = 0; 656 APoolInfo newArg = host.inPool(_constantPool); 657 if (null != newArg) { 658 // yes, mark for deletion 659 indices[j] = _constantPool.indexOf(newArg); 660 } 661 662 return null; 663 } 664 665 public Object classCase(ClassPoolInfo host, Object o) { 666 return referencedCase(host, o); 667 } 668 669 public Object nameAndTypeInfo(NameAndTypePoolInfo host, Object o) { 670 return referencedCase(host, o); 671 } 672 673 private Object referencedCase(APoolInfo referencedHost, Object o) { 674 // check if this object is already in the pool 675 indices[j] = 0; 676 final APoolInfo newArg = referencedHost.inPool(_constantPool); 677 if (null != newArg) { 678 // yes, mark for deletion 679 indices[j] = _constantPool.indexOf(newArg); 680 681 // update references 682 for(APoolInfo cpi : items) { 683 cpi.execute(new AValueReferencePoolInfoVisitor<Object, Object>() { 684 public Object valueCase(APoolInfo host, Object o) { 685 // do nothing, value objects don't have references 686 return null; 687 } 688 689 public Object emptyCase(EmptyPoolInfo host, Object o) { 690 // do nothing 691 return null; 692 } 693 694 public Object refCase(APoolInfo host, Object o) { 695 // do nothing, these objects don't have Class or NameAndType references 696 return null; 697 } 698 699 public Object fieldCase(FieldPoolInfo host, Object o) { 700 // field objects have Class and NameAndType references 701 return classNameTypeCase(host, o); 702 } 703 704 public Object methodCase(MethodPoolInfo host, Object o) { 705 // method objects have Class and NameAndType references 706 return classNameTypeCase(host, o); 707 } 708 709 public Object interfaceMethodCase(InterfaceMethodPoolInfo host, Object o) { 710 // interface method objects have Class and NameAndType references 711 return classNameTypeCase(host, o); 712 } 713 714 public Object classNameTypeCase(AClassNameTypePoolInfo host, Object o) { 715 // ClassNameType objects have a Class and a NameAndType references 716 if (host.getClassInfo() == newArg) { 717 // this is affected, update it 718 host.setClassInfo((ClassPoolInfo)newArg); 719 } 720 if (host.getNameAndType() == newArg) { 721 // this is affected, update it 722 host.setNameAndType((NameAndTypePoolInfo)newArg); 723 } 724 return null; 725 } 726 }, null); 727 } 728 } 729 730 return null; 731 } 732 }, null); 733 } 734 735 // add new items to the pool 736 for(int i = 0; i < items.length; ++i) { 737 if (0 == indices[i]) { 738 _constantPool.add(items[i]); 739 // add empty item for long and double 740 items[i].execute(new NoOpPoolInfoVisitor<Object, Object>() { 741 public Object longCase(LongPoolInfo host, Object o) { 742 _constantPool.add(EmptyPoolInfo.singleton()); 743 return null; 744 } 745 746 public Object doubleCase(DoublePoolInfo host, Object o) { 747 _constantPool.add(EmptyPoolInfo.singleton()); 748 return null; 749 } 750 }, null); 751 indices[i] = _constantPool.indexOf(items[i]); 752 } 753 } 754 755 return indices; 756 } 757 758 /** 759 * Add an attribute to the class. 760 * 761 * @param newAttribute new attribute 762 */ 763 public void addAttribute(AAttributeInfo newAttribute) { 764 _attributes.add(newAttribute); 765 } 766 767 /** 768 * Return the attribute with the specified name. 769 * 770 * @param name attribute name 771 * 772 * @return attribute or null if not found 773 */ 774 public AAttributeInfo getAttribute(String name) { 775 if (0 == _attributes.size()) { 776 return null; 777 } 778 for(AAttributeInfo attr : _attributes) { 779 if (0 == name.compareTo(attr.getName().toString())) { 780 return attr; 781 } 782 } 783 return null; 784 } 785 786 /** 787 * Accessor for the minor version. 788 * 789 * @return minor version 790 */ 791 public short getMinorVersion() { 792 return _minorVersion; 793 } 794 795 /** 796 * Mutator for the minor version. 797 * 798 * @param minorVersion new minor version 799 */ 800 public void setMinorVersion(short minorVersion) { 801 _minorVersion = minorVersion; 802 } 803 804 /** 805 * Accessor for the major version. 806 * 807 * @return major version 808 */ 809 public short getMajorVersion() { 810 return _majorVersion; 811 } 812 813 /** 814 * Mutator for the major version. 815 * 816 * @param majorVersion new major version 817 */ 818 public void setMajorVersion(short majorVersion) { 819 _majorVersion = majorVersion; 820 } 821 822 /** 823 * Accessor for the class access flags. 824 * 825 * @return access flags 826 */ 827 public short getClassAccessFlags() { 828 return _classAccessFlags; 829 } 830 831 /** 832 * Mutator for the class access flags. 833 * 834 * @param classAccessFlags new flags 835 */ 836 public void setClassAccessFlags(short classAccessFlags) { 837 _classAccessFlags = classAccessFlags; 838 } 839 840 /** 841 * Accessor for the superclass. 842 * 843 * @return superclass information 844 */ 845 public ClassPoolInfo getSuperClass() { 846 return _superClass; 847 } 848 849 /** 850 * Mutator for the superclass. 851 * @param cpi superclass information 852 */ 853 public void setSuperClass(ClassPoolInfo cpi) { 854 _superClass = cpi; 855 } 856 857 /** 858 * Accessor for this class. 859 * 860 * @return this class 861 */ 862 public ClassPoolInfo getThisClass() { 863 return _thisClass; 864 } 865 /** 866 * Mutator for the this class. 867 * @param cpi this class information 868 */ 869 public void setThisClass(ClassPoolInfo cpi) { 870 _thisClass = cpi; 871 } 872 873 874 /** 875 * Accessor for the interface list. 876 * 877 * @return interface list 878 */ 879 public ArrayList<ClassPoolInfo> getInterfaces() { 880 return _interfaces; 881 } 882 883 /** 884 * Accessor for the fields list. 885 * 886 * @return fields list 887 */ 888 public ArrayList<FieldInfo> getFields() { 889 return _fields; 890 } 891 892 /** 893 * Accessor for the methods list. 894 * 895 * @return methods list 896 */ 897 public ArrayList<MethodInfo> getMethods() { 898 return _methods; 899 } 900 901 /** 902 * Accessor for the attributes list. 903 * 904 * @return methods list 905 */ 906 public ArrayList<AAttributeInfo> getAttributes() { 907 return _attributes; 908 } 909 910 /** 911 * Accessor for the constant pool. 912 * 913 * @return methods list 914 */ 915 public ConstantPool getConstantPool() { 916 return _constantPool; 917 } 918 919 /** 920 * Add the constant pool items for a method "methodName:methodDescriptor" in class "className". 921 * 922 * @param className class name 923 * @param methodName method name 924 * @param methodDescriptor method descriptor 925 * 926 * @return constant pool index of method info 927 */ 928 public short addMethodToConstantPool(String className, String methodName, String methodDescriptor) { 929 ConstantPool cp = getConstantPool(); 930 931 short[] l; 932 933 // add a new name for the monitor class 934 AUTFPoolInfo monitorClassName = new ASCIIPoolInfo(className, cp); 935 l = addConstantPoolItems(new APoolInfo[]{monitorClassName}); 936 // Debug.out.println("monitorClassName index = " + l[0]); 937 monitorClassName = getConstantPoolItem(l[0]).execute(CheckUTFVisitor.singleton(), null); 938 939 // add a new class for the monitor class 940 ClassPoolInfo monitorClass = new ClassPoolInfo(monitorClassName, cp); 941 l = addConstantPoolItems(new APoolInfo[]{monitorClass}); 942 // Debug.out.println("monitorClass index = " + l[0]); 943 monitorClass = getConstantPoolItem(l[0]).execute(CheckClassVisitor.singleton(), null); 944 945 // add a new method name for the method 946 AUTFPoolInfo methodNameInfo = new ASCIIPoolInfo(methodName, cp); 947 l = addConstantPoolItems(new APoolInfo[]{methodNameInfo}); 948 // Debug.out.println("methodNameInfo index = " + l[0]); 949 methodNameInfo = getConstantPoolItem(l[0]).execute(CheckUTFVisitor.singleton(), null); 950 951 // add a new type name for the method 952 AUTFPoolInfo methodTypeName = new ASCIIPoolInfo(methodDescriptor, cp); 953 l = addConstantPoolItems(new APoolInfo[]{methodTypeName}); 954 // Debug.out.println("methodTypeName index = " + l[0]); 955 methodTypeName = getConstantPoolItem(l[0]).execute(CheckUTFVisitor.singleton(), null); 956 957 // add a new name-and-type for the method 958 NameAndTypePoolInfo methodNaT = new NameAndTypePoolInfo(methodNameInfo, methodTypeName, cp); 959 l = addConstantPoolItems(new APoolInfo[]{methodNaT}); 960 // Debug.out.println("methodNaT index = " + l[0]); 961 methodNaT = getConstantPoolItem(l[0]).execute(CheckNameAndTypeVisitor.singleton(), null); 962 963 // add a new method info for the method 964 MethodPoolInfo method = new MethodPoolInfo(monitorClass, methodNaT, cp); 965 l = addConstantPoolItems(new APoolInfo[]{method}); 966 // Debug.out.println("method index = " + l[0]); 967 method = getConstantPoolItem(l[0]).execute(CheckMethodVisitor.singleton(), null); 968 969 return l[0]; 970 } 971 972 /** 973 * Add the constant pool items for a field "fieldName:fieldDescriptor" in class "className". 974 * 975 * @param className class name 976 * @param fieldName field name 977 * @param fieldDescriptor field descriptor 978 * @param addToFields true if a new field should be added to the fields list as well 979 * @param accessFlags access flags (only if addToFields is true) 980 * 981 * @return constant pool index of field info 982 */ 983 public short addField(String className, String fieldName, String fieldDescriptor, boolean addToFields, 984 short accessFlags) { 985 ConstantPool cp = getConstantPool(); 986 987 short[] l; 988 989 // add a new name 990 AUTFPoolInfo fieldClassName = new ASCIIPoolInfo(className, cp); 991 l = addConstantPoolItems(new APoolInfo[]{fieldClassName}); 992 fieldClassName = getConstantPoolItem(l[0]).execute(CheckUTFVisitor.singleton(), null); 993 994 // add a new class 995 ClassPoolInfo fieldClass = new ClassPoolInfo(fieldClassName, cp); 996 l = addConstantPoolItems(new APoolInfo[]{fieldClass}); 997 fieldClass = getConstantPoolItem(l[0]).execute(CheckClassVisitor.singleton(), null); 998 999 // add a new field name for the field 1000 AUTFPoolInfo fieldNameInfo = new ASCIIPoolInfo(fieldName, cp); 1001 l = addConstantPoolItems(new APoolInfo[]{fieldNameInfo}); 1002 fieldNameInfo = getConstantPoolItem(l[0]).execute(CheckUTFVisitor.singleton(), null); 1003 1004 // add a new type name for the field 1005 AUTFPoolInfo fieldTypeName = new ASCIIPoolInfo(fieldDescriptor, cp); 1006 l = addConstantPoolItems(new APoolInfo[]{fieldTypeName}); 1007 fieldTypeName = getConstantPoolItem(l[0]).execute(CheckUTFVisitor.singleton(), null); 1008 1009 // add a new name-and-type for the field 1010 NameAndTypePoolInfo fieldNaT = new NameAndTypePoolInfo(fieldNameInfo, fieldTypeName, cp); 1011 l = addConstantPoolItems(new APoolInfo[]{fieldNaT}); 1012 fieldNaT = getConstantPoolItem(l[0]).execute(CheckNameAndTypeVisitor.singleton(), null); 1013 1014 // add a new field info for the field 1015 FieldPoolInfo field = new FieldPoolInfo(fieldClass, fieldNaT, cp); 1016 l = addConstantPoolItems(new APoolInfo[]{field}); 1017 field = getConstantPoolItem(l[0]).execute(new ADefaultPoolInfoVisitor<FieldPoolInfo, Object>() { 1018 public FieldPoolInfo defaultCase(APoolInfo host, Object param) { 1019 throw new ClassFormatError("Info is of type " + host.getClass().getName() + ", needs to be FieldPoolInfo"); 1020 } 1021 1022 public FieldPoolInfo fieldCase(FieldPoolInfo host, Object param) { 1023 return host; 1024 } 1025 }, null); 1026 1027 if (addToFields) { 1028 FieldInfo fi = new FieldInfo(accessFlags, fieldNameInfo, fieldTypeName, new SourceFileAttributeInfo[] {}); 1029 getFields().add(fi); 1030 } 1031 1032 return l[0]; 1033 } 1034 1035 /** 1036 * Find the method info in the constant pool for a method "methodName:methodDescriptor" in class "className". 1037 * 1038 * @param className class name 1039 * @param methodName method name 1040 * @param methodDescriptor method descriptor 1041 * 1042 * @return constant pool index of the method, or 0 if not found 1043 */ 1044 public short findMethodInConstantPool(String className, String methodName, String methodDescriptor) { 1045 ConstantPool cp = getConstantPool(); 1046 1047 short[] l; 1048 APoolInfo newArg; 1049 1050 // add a new name for the monitor class 1051 AUTFPoolInfo monitorClassName = new ASCIIPoolInfo(className, cp); 1052 newArg = (AUTFPoolInfo)monitorClassName.inPool(cp); 1053 if (null == newArg) { 1054 // not found 1055 return 0; 1056 } 1057 monitorClassName = newArg.execute(CheckUTFVisitor.singleton(), null); 1058 1059 // add a new class for the monitor class 1060 ClassPoolInfo monitorClass = new ClassPoolInfo(monitorClassName, cp); 1061 newArg = monitorClass.inPool(cp); 1062 if (null == newArg) { 1063 // not found 1064 return 0; 1065 } 1066 monitorClass = newArg.execute(CheckClassVisitor.singleton(), null); 1067 1068 // add a new method name for the method 1069 AUTFPoolInfo methodNameInfo = new ASCIIPoolInfo(methodName, cp); 1070 newArg = methodNameInfo.inPool(cp); 1071 if (null == newArg) { 1072 // not found 1073 return 0; 1074 } 1075 methodNameInfo = newArg.execute(CheckUTFVisitor.singleton(), null); 1076 1077 // add a new type name for the method 1078 AUTFPoolInfo methodTypeName = new ASCIIPoolInfo(methodDescriptor, cp); 1079 newArg = methodTypeName.inPool(cp); 1080 if (null == newArg) { 1081 // not found 1082 return 0; 1083 } 1084 methodTypeName = newArg.execute(CheckUTFVisitor.singleton(), null); 1085 1086 // add a new name-and-type for the method 1087 NameAndTypePoolInfo methodNaT = new NameAndTypePoolInfo(methodNameInfo, methodTypeName, cp); 1088 newArg = methodNaT.inPool(cp); 1089 if (null == newArg) { 1090 // not found 1091 return 0; 1092 } 1093 methodNaT = newArg.execute(CheckNameAndTypeVisitor.singleton(), null); 1094 1095 // add a new method info for the method 1096 MethodPoolInfo method = new MethodPoolInfo(monitorClass, methodNaT, cp); 1097 newArg = method.inPool(cp); 1098 if (null == newArg) { 1099 // not found 1100 return 0; 1101 } 1102 method = newArg.execute(CheckMethodVisitor.singleton(), null); 1103 1104 return cp.indexOf(method); 1105 } 1106 }