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