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    }