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 }