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    }