001    package edu.rice.cs.cunit.classFile.attributes;
002    
003    import edu.rice.cs.cunit.classFile.constantPool.AUTFPoolInfo;
004    import edu.rice.cs.cunit.classFile.constantPool.ConstantPool;
005    import edu.rice.cs.cunit.classFile.constantPool.APoolInfo;
006    import edu.rice.cs.cunit.classFile.constantPool.visitors.CheckUTFVisitor;
007    import edu.rice.cs.cunit.classFile.code.instructions.LineNumberTable;
008    import edu.rice.cs.cunit.classFile.ClassFileTools;
009    import edu.rice.cs.cunit.util.Types;
010    
011    import java.io.ByteArrayOutputStream;
012    import java.io.IOException;
013    import java.util.List;
014    import java.util.ArrayList;
015    import java.util.Arrays;
016    
017    /**
018     * Represents an abstract Annotations attribute in a class file.
019     *
020     * @author Mathias Ricken
021     */
022    public abstract class AAnnotationsAttributeInfo extends AAttributeInfo {
023        /**
024         * Storage class for annotations.
025         */
026        public static class Annotation {
027            /**
028             * Storage class for a member value.
029             */
030            public static abstract class AMemberValue {
031                /**
032                 * Type tag.
033                 */
034                public char tag;
035    
036                /**
037                 * Creates a new member value.
038                 * @param tag _type tag of this value
039                 */
040                protected AMemberValue(char tag) {
041                    this.tag = tag;
042                }
043    
044                /**
045                 * Returns the size of this value.
046                 * @return size in bytes
047                 */
048                public abstract int getSize();
049    
050                /**
051                 * Returns the tag character of this value.
052                 * @return tag
053                 */
054                public char getTag() {
055                    return tag;
056                }
057    
058                /**
059                 * Writes this value into the stream.
060                 * @param cp constant pool
061                 * @param baos stream
062                 * @throws IOException
063                 */
064                public abstract void writeToByteArrayOutputStream(ConstantPool cp, ByteArrayOutputStream baos) throws IOException;
065    
066                /**
067                 * Parses member value data and returns a member value.
068                 * @param cp constant pool
069                 * @param data data array
070                 * @param start start index in data array
071                 * @return parsed member value
072                 */
073                public static AMemberValue read(ConstantPool cp, byte[] data, int start) {
074                    char tag = (char)data[start];
075                    if ("BCDFIJSZs".indexOf(tag) != -1) {
076                        return new Annotation.ConstantMemberValue(tag, cp.get(Types.ushortFromBytes(data, start + 1)));
077                    }
078                    else if (tag == 'e') {
079                        return new Annotation.EnumMemberValue(tag, cp.get(Types.ushortFromBytes(data, start + 1))
080                            .execute(CheckUTFVisitor.singleton(), null), cp.get(Types.ushortFromBytes(data, start + 3))
081                            .execute(CheckUTFVisitor.singleton(), null));
082                    }
083                    else if (tag == 'c') {
084                        return new Annotation.ClassMemberValue(tag, cp.get(Types.ushortFromBytes(data, start + 1)).
085                            execute(CheckUTFVisitor.singleton(), null));
086                    }
087                    else if (tag == '@') {
088                        return new Annotation.AnnotationMemberValue(tag, new Annotation(cp, data, start + 1));
089                    }
090                    else if (tag == '[') {
091                        return new Annotation.ArrayMemberValue(cp, data, start);
092                    }
093                    else {
094                        throw new ClassFormatError("Unknown member value tag: " + tag);
095                    }
096                }
097    
098                /**
099                 * Returns a string representation of the object like it would be seen in a Java listing.
100                 * @return a string representation of the object.
101                 */
102                public abstract String toStringJava();
103    
104                /**
105                 * Execute a visitor.
106                 * @param v visitor
107                 * @param param visitor-specific parameter
108                 * @return visitor-specific return value
109                 */
110                public abstract <R, P> R execute(IMemberValueVisitor<R, P> v, P param);
111    
112    
113                /**
114                 * Returns a hash code value for the object.
115                 * @return a hash code value for this object.
116                 */
117                public abstract int hashCode();
118    
119                /**
120                 * Indicates whether some other object is "equal to" this one.
121                 * @param o the reference object with which to compare.
122                 * @return <code>true</code> if this object is the same as the obj argument; <code>false</code> otherwise.
123                 */
124                public abstract boolean equals(Object o);
125            }
126    
127            /**
128             * Visitor interface for member values.
129             */
130            public static interface IMemberValueVisitor<R, P> {
131                /**
132                 * Case for constants.
133                 * @param host constant member
134                 * @param param visitor-specific parameter
135                 * @return visitor-specific return value
136                 */
137                public abstract R constantMemberCase(ConstantMemberValue host, P param);
138    
139                /**
140                 * Case for enums.
141                 * @param host enum member
142                 * @param param visitor-specific parameter
143                 * @return visitor-specific return value
144                 */
145                public abstract R enumMemberCase(EnumMemberValue host, P param);
146    
147                /**
148                 * Case for classes.
149                 * @param host class member
150                 * @param param visitor-specific parameter
151                 * @return visitor-specific return value
152                 */
153                public abstract R classMemberCase(ClassMemberValue host, P param);
154    
155                /**
156                 * Case for annotations.
157                 * @param host annotation member
158                 * @param param visitor-specific parameter
159                 * @return visitor-specific return value
160                 */
161                public abstract R annotationMemberCase(AnnotationMemberValue host, P param);
162    
163                /**
164                 * Case for arrays.
165                 * @param host array member
166                 * @param param visitor-specific parameter
167                 * @return visitor-specific return value
168                 */
169                public abstract R arrayMemberCase(ArrayMemberValue host, P param);
170            }
171    
172            /**
173             * Default visitor where all cases delegate to an abstract default case.
174             */
175            public static abstract class ADefaultMemberValueVisitor<R, P> implements IMemberValueVisitor<R, P> {
176                /**
177                 * Default case.
178                 *
179                 * @param host  member
180                 * @param param visitor-specific parameter
181                 *
182                 * @return visitor-specific return value
183                 */
184                public abstract R defaultCase(AMemberValue host, P param);
185    
186                /**
187                 * Case for constants.
188                 *
189                 * @param host  constant member
190                 * @param param visitor-specific parameter
191                 *
192                 * @return visitor-specific return value
193                 */
194                public R constantMemberCase(ConstantMemberValue host, P param) {
195                    return defaultCase(host, param);
196                }
197    
198                /**
199                 * Case for enums.
200                 *
201                 * @param host  enum member
202                 * @param param visitor-specific parameter
203                 *
204                 * @return visitor-specific return value
205                 */
206                public R enumMemberCase(EnumMemberValue host, P param) {
207                    return defaultCase(host, param);
208                }
209    
210                /**
211                 * Case for classes.
212                 *
213                 * @param host  class member
214                 * @param param visitor-specific parameter
215                 *
216                 * @return visitor-specific return value
217                 */
218                public R classMemberCase(ClassMemberValue host, P param) {
219                    return defaultCase(host, param);
220                }
221    
222                /**
223                 * Case for annotations.
224                 *
225                 * @param host  annotation member
226                 * @param param visitor-specific parameter
227                 *
228                 * @return visitor-specific return value
229                 */
230                public R annotationMemberCase(AnnotationMemberValue host, P param) {
231                    return defaultCase(host, param);
232                }
233    
234                /**
235                 * Case for arrays.
236                 *
237                 * @param host  array member
238                 * @param param visitor-specific parameter
239                 *
240                 * @return visitor-specific return value
241                 */
242                public R arrayMemberCase(ArrayMemberValue host, P param) {
243                    return defaultCase(host, param);
244                }
245            }
246    
247            public static class CheckConstantMemberVisitor extends ADefaultMemberValueVisitor<ConstantMemberValue, Object> {
248                /**
249                 * Default case. Throws exception.
250                 *
251                 * @param host  non-constant member
252                 * @param param visitor-specific parameter
253                 *
254                 * @return does not return
255                 */
256                public ConstantMemberValue defaultCase(AMemberValue host, Object param) {
257                    throw new RuntimeException("Constant annotation member value expected.");
258                }
259    
260                /**
261                 * Case for constants.
262                 *
263                 * @param host  constant member
264                 * @param param visitor-specific parameter
265                 *
266                 * @return the host
267                 */
268                public ConstantMemberValue constantMemberCase(ConstantMemberValue host, Object param) {
269                    return host;
270                }
271    
272                /**
273                 * Singleton constructor.
274                 */
275                private CheckConstantMemberVisitor() {
276                }
277    
278                /**
279                 * Singleton instance.
280                 */
281                private static CheckConstantMemberVisitor _instance = new CheckConstantMemberVisitor();
282    
283                /**
284                 * Singleton accessor.
285                 *
286                 * @return singleton
287                 */
288                public static CheckConstantMemberVisitor singleton() {
289                    return _instance;
290                }
291            }
292    
293            /**
294             * Storage class for constants.
295             */
296            public static class ConstantMemberValue extends Annotation.AMemberValue {
297                /**
298                 * Constant value.
299                 */
300                APoolInfo constValue;
301    
302                /**
303                 * Creates a new constant value.
304                 * @param tag _type tag
305                 * @param constValue constant value
306                 */
307                public ConstantMemberValue(char tag, APoolInfo constValue) {
308                    super(tag);
309                    this.constValue = constValue;
310                }
311    
312                /**
313                 * Returns the size of this value.
314                 * @return size in bytes
315                 */
316                public int getSize() {
317                    return 3;
318                }
319    
320                /**
321                 * Writes this value into the stream.
322                 * @param cp constant pool
323                 * @param baos stream
324                 * @throws IOException
325                 */
326                public void writeToByteArrayOutputStream(ConstantPool cp, ByteArrayOutputStream baos) throws IOException {
327                    baos.write(tag);
328                    baos.write(Types.bytesFromShort(cp.indexOf(constValue)));
329                }
330    
331                /**
332                 * Returns a string representation of the object.
333                 * @return a string representation of the object.
334                 */
335                public String toString() {
336                    return constValue.toString();
337                }
338    
339                /**
340                 * Returns a string representation of the object like it would be seen in a Java listing.
341                 * @return a string representation of the object.
342                 */
343                public String toStringJava() {
344                    switch(tag) {
345                        case 's': return "\""+constValue.toString()+"\"";
346                        case 'F': return constValue.toString()+"f";
347                        default: return constValue.toString();
348                    }
349                }
350    
351                /**
352                 * Execute a visitor.
353                 *
354                 * @param v     visitor
355                 * @param param visitor-specific parameter
356                 *
357                 * @return visitor-specific return value
358                 */
359                public <R, P> R execute(IMemberValueVisitor<R, P> v, P param) {
360                    return v.constantMemberCase(this, param);
361                }
362    
363                /**
364                 * Accessor for the constant value.
365                 * @return constant value
366                 */
367                public APoolInfo getConstValue() {
368                    return constValue;
369                }
370    
371    
372                /**
373                 * Indicates whether some other object is "equal to" this one.
374                 * @param o the reference object with which to compare.
375                 * @return <code>true</code> if this object is the same as the obj argument; <code>false</code> otherwise.
376                 */
377                public boolean equals(Object o) {
378                    if (this == o) {
379                        return true;
380                    }
381                    if (o == null || getClass() != o.getClass()) {
382                        return false;
383                    }
384    
385                    ConstantMemberValue that = (ConstantMemberValue)o;
386    
387                    if (constValue != null ? !constValue.equals(that.constValue) : that.constValue != null) {
388                        return false;
389                    }
390    
391                    return true;
392                }
393    
394                /**
395                 * Returns a hash code value for the object.
396                 * @return a hash code value for this object.
397                 */
398                public int hashCode() {
399                    return (constValue != null ? constValue.hashCode() : 0);
400                }
401            }
402    
403            /**
404             * Storage class for an enum.
405             */
406            public static class EnumMemberValue extends Annotation.AMemberValue {
407                /**
408                 * Name of the enum class.
409                 */
410                AUTFPoolInfo typeName;
411                /**
412                 * Name of the enum member.
413                 */
414                AUTFPoolInfo constValue;
415    
416                /**
417                 * Creates a new enum value.
418                 * @param tag _type tag
419                 * @param typeName name of enum class
420                 * @param constValue name of enum member
421                 */
422                public EnumMemberValue(char tag, AUTFPoolInfo typeName, AUTFPoolInfo constValue) {
423                    super(tag);
424                    this.typeName = typeName;
425                    this.constValue = constValue;
426                }
427    
428                /**
429                 * Returns the size of this value.
430                 * @return size in bytes
431                 */
432                public int getSize() {
433                    return 5;
434                }
435    
436                /**
437                 * Writes this value into the stream.
438                 * @param cp constant pool
439                 * @param baos stream
440                 * @throws IOException
441                 */
442                public void writeToByteArrayOutputStream(ConstantPool cp, ByteArrayOutputStream baos) throws IOException {
443                    baos.write(tag);
444                    baos.write(Types.bytesFromShort(cp.indexOf(typeName)));
445                    baos.write(Types.bytesFromShort(cp.indexOf(constValue)));
446                }
447    
448                /**
449                 * Returns a string representation of the object.
450                 * @return a string representation of the object.
451                 */
452                public String toString() {
453                    return typeName.toString()+"."+constValue.toString();
454                }
455    
456                /**
457                 * Returns a string representation of the object like it would be seen in a Java listing.
458                 * @return a string representation of the object.
459                 */
460                public String toStringJava() {
461                    String s = ClassFileTools.getTypeString(typeName.toString(),"").replace('$','.');
462                    return s.substring(0, s.length()-1)+"."+constValue.toString();
463                }
464    
465                /**
466                 * Execute a visitor.
467                 *
468                 * @param v     visitor
469                 * @param param visitor-specific parameter
470                 *
471                 * @return visitor-specific return value
472                 */
473                public <R, P> R execute(IMemberValueVisitor<R, P> v, P param) {
474                    return v.enumMemberCase(this, param);
475                }
476    
477                /**
478                 * Accessor for the type name.
479                 * @return type name
480                 */
481                public AUTFPoolInfo getTypeName() {
482                    return typeName;
483                }
484    
485                /**
486                 * Accessor for the constant value.
487                 * @return constant value
488                 */
489                public AUTFPoolInfo getConstValue() {
490                    return constValue;
491                }
492    
493    
494                /**
495                 * Indicates whether some other object is "equal to" this one.
496                 * @param o the reference object with which to compare.
497                 * @return <code>true</code> if this object is the same as the obj argument; <code>false</code> otherwise.
498                 */
499                public boolean equals(Object o) {
500                    if (this == o) {
501                        return true;
502                    }
503                    if (o == null || getClass() != o.getClass()) {
504                        return false;
505                    }
506    
507                    EnumMemberValue that = (EnumMemberValue)o;
508    
509                    if (constValue != null ? !constValue.equals(that.constValue) : that.constValue != null) {
510                        return false;
511                    }
512                    if (typeName != null ? !typeName.equals(that.typeName) : that.typeName != null) {
513                        return false;
514                    }
515    
516                    return true;
517                }
518    
519                /**
520                 * Returns a hash code value for the object.
521                 * @return a hash code value for this object.
522                 */
523                public int hashCode() {
524                    int result;
525                    result = (typeName != null ? typeName.hashCode() : 0);
526                    result = 31 * result + (constValue != null ? constValue.hashCode() : 0);
527                    return result;
528                }
529            }
530    
531            /**
532             * Storage class for a class value.
533             */
534            public static class ClassMemberValue extends Annotation.AMemberValue {
535                /**
536                 * Class name info.
537                 * NOTE: Apparently this is an UTF item and not a CLASS item as documented. 
538                 */
539                AUTFPoolInfo classNameInfo;
540    
541                /**
542                 * Creates a new class value.
543                 * @param tag _type tag
544                 * @param classNameInfo class name info
545                 */
546                public ClassMemberValue(char tag, AUTFPoolInfo classNameInfo) {
547                    super(tag);
548                    this.classNameInfo = classNameInfo;
549                }
550    
551                /**
552                 * Returns the size of this value.
553                 * @return size in bytes
554                 */
555                public int getSize() {
556                    return 3;
557                }
558    
559                /**
560                 * Writes this value into the stream.
561                 * @param cp constant pool
562                 * @param baos stream
563                 * @throws IOException
564                 */
565                public void writeToByteArrayOutputStream(ConstantPool cp, ByteArrayOutputStream baos) throws IOException {
566                    baos.write(tag);
567                    baos.write(Types.bytesFromShort(cp.indexOf(classNameInfo)));
568                }
569    
570                /**
571                 * Returns a string representation of the object.
572                 * @return a string representation of the object.
573                 */
574                public String toString() {
575                    return classNameInfo.toString();
576                }
577    
578                /**
579                 * Returns a string representation of the object like it would be seen in a Java listing.
580                 * @return a string representation of the object.
581                 */
582                public String toStringJava() {
583                    String s = ClassFileTools.getTypeString(classNameInfo.toString(),"").replace('$','.');
584                    return s.substring(0, s.length()-1)+".class";
585                }
586    
587                /**
588                 * Execute a visitor.
589                 *
590                 * @param v     visitor
591                 * @param param visitor-specific parameter
592                 *
593                 * @return visitor-specific return value
594                 */
595                public <R, P> R execute(IMemberValueVisitor<R, P> v, P param) {
596                    return v.classMemberCase(this, param);
597                }
598    
599                /**
600                 * Accessor for the class name.
601                 * @return class name
602                 */
603                public AUTFPoolInfo getClassName() {
604                    return classNameInfo;
605                }
606    
607    
608                /**
609                 * Indicates whether some other object is "equal to" this one.
610                 * @param o the reference object with which to compare.
611                 * @return <code>true</code> if this object is the same as the obj argument; <code>false</code> otherwise.
612                 */
613                public boolean equals(Object o) {
614                    if (this == o) {
615                        return true;
616                    }
617                    if (o == null || getClass() != o.getClass()) {
618                        return false;
619                    }
620    
621                    ClassMemberValue that = (ClassMemberValue)o;
622    
623                    if (classNameInfo != null ? !classNameInfo.equals(that.classNameInfo) : that.classNameInfo != null) {
624                        return false;
625                    }
626    
627                    return true;
628                }
629    
630                /**
631                 * Returns a hash code value for the object.
632                 * @return a hash code value for this object.
633                 */
634                public int hashCode() {
635                    return (classNameInfo != null ? classNameInfo.hashCode() : 0);
636                }
637            }
638    
639            /**
640             * Storage class for an annotation value.
641             */
642            public static class AnnotationMemberValue extends Annotation.AMemberValue {
643                /**
644                 * Annotation value.
645                 */
646                Annotation annotation;
647    
648                /**
649                 * Creates a new annotation value.
650                 * @param tag _type tag
651                 * @param annotation annotation value
652                 */
653                public AnnotationMemberValue(char tag, Annotation annotation) {
654                    super(tag);
655                    this.annotation = annotation;
656                }
657    
658                /**
659                 * Returns the size of this value.
660                 * @return size in bytes
661                 */
662                public int getSize() {
663                    return 1 + annotation.getSize();
664                }
665    
666                /**
667                 * Writes this value into the stream.
668                 * @param cp constant pool
669                 * @param baos stream
670                 * @throws IOException
671                 */
672                public void writeToByteArrayOutputStream(ConstantPool cp, ByteArrayOutputStream baos) throws IOException {
673                    baos.write(tag);
674                    annotation.writeToByteArrayOutputStream(cp,baos);
675                }
676    
677                /**
678                 * Returns a string representation of the object.
679                 * @return a string representation of the object.
680                 */
681                public String toString() {
682                    return annotation.toString();
683                }
684    
685                /**
686                 * Returns a string representation of the object like it would be seen in a Java listing.
687                 * @return a string representation of the object.
688                 */
689                public String toStringJava() {
690                    return annotation.toStringJava();
691                }
692    
693                /**
694                 * Execute a visitor.
695                 *
696                 * @param v     visitor
697                 * @param param visitor-specific parameter
698                 *
699                 * @return visitor-specific return value
700                 */
701                public <R, P> R execute(IMemberValueVisitor<R, P> v, P param) {
702                    return v.annotationMemberCase(this, param);
703                }
704    
705                /**
706                 * Accessor for the annotation.
707                 * @return annotation
708                 */
709                public Annotation getAnnotation() {
710                    return annotation;
711                }
712    
713    
714                /**
715                 * Indicates whether some other object is "equal to" this one.
716                 * @param o the reference object with which to compare.
717                 * @return <code>true</code> if this object is the same as the obj argument; <code>false</code> otherwise.
718                 */
719                public boolean equals(Object o) {
720                    if (this == o) {
721                        return true;
722                    }
723                    if (o == null || getClass() != o.getClass()) {
724                        return false;
725                    }
726    
727                    AnnotationMemberValue that = (AnnotationMemberValue)o;
728    
729                    if (annotation != null ? !annotation.equals(that.annotation) : that.annotation != null) {
730                        return false;
731                    }
732    
733                    return true;
734                }
735    
736                /**
737                 * Returns a hash code value for the object.
738                 * @return a hash code value for this object.
739                 */
740                public int hashCode() {
741                    return (annotation != null ? annotation.hashCode() : 0);
742                }
743            }
744    
745            /**
746             * Storage class for an array.
747             */
748            public static class ArrayMemberValue extends Annotation.AMemberValue {
749                /**
750                 * Number of entries in array.
751                 */
752                int numEntries;
753                /**
754                 * Array of values.
755                 */
756                AMemberValue[] entries;
757    
758                /**
759                 * Creates a new array.
760                 * @param tag _type tag
761                 * @param numEntries number of entries
762                 * @param entries array of entries
763                 */
764                public ArrayMemberValue(char tag, int numEntries, AMemberValue[] entries) {
765                    super(tag);
766                    assert(numEntries <= 0xffff);
767                    this.numEntries = numEntries;
768                    this.entries = entries;
769                }
770    
771                /**
772                 * Creates a new array.
773                 * @param cp constant pool
774                 * @param data data arrat
775                 * @param start start index in array
776                 */
777                public ArrayMemberValue(ConstantPool cp, byte[] data, int start) {
778                    super((char)data[start]);
779                    numEntries = Types.ushortFromBytes(data, start + 1);
780                    entries = new Annotation.AMemberValue[numEntries];
781                    int index = start + 3;
782                    for (int i=0; i<numEntries; ++i) {
783                        entries[i] = Annotation.AMemberValue.read(cp, data, index);
784                        index += entries[i].getSize();
785                    }
786                }
787    
788                /**
789                 * Returns the size of this value.
790                 * @return size in bytes
791                 */
792                public int getSize() {
793                    int accum = 3;
794                    for (Annotation.AMemberValue mv:entries) {
795                        accum += mv.getSize();
796                    }
797                    return accum;
798                }
799    
800                /**
801                 * Writes this value into the stream.
802                 * @param cp constant pool
803                 * @param baos stream
804                 * @throws IOException
805                 */
806                public void writeToByteArrayOutputStream(ConstantPool cp, ByteArrayOutputStream baos) throws IOException {
807                    baos.write(tag);
808                    baos.write(Types.bytesFromShort((short)(numEntries & 0xffff)));
809                    for (Annotation.AMemberValue mv:entries) {
810                        mv.writeToByteArrayOutputStream(cp, baos);
811                    }
812                }
813    
814                /**
815                 * Returns a string representation of the object.
816                 * @return a string representation of the object.
817                 */
818                public String toString() {
819                    StringBuilder sb = new StringBuilder();;
820                    sb.append("{");
821                    boolean first = true;
822                    for(AMemberValue mv:entries) {
823                        if (first) {
824                            first = false;
825                        }
826                        else {
827                            sb.append(", ");
828                        }
829                        sb.append(mv.toString());
830                    }
831                    sb.append("}");
832                    return sb.toString();
833                }
834    
835                /**
836                 * Returns a string representation of the object like it would be seen in a Java listing.
837                 * @return a string representation of the object.
838                 */
839                public String toStringJava() {
840                    return toString();
841                }
842    
843                /**
844                 * Execute a visitor.
845                 *
846                 * @param v     visitor
847                 * @param param visitor-specific parameter
848                 *
849                 * @return visitor-specific return value
850                 */
851                public <R, P> R execute(IMemberValueVisitor<R, P> v, P param) {
852                    return v.arrayMemberCase(this, param);
853                }
854    
855                /**
856                 * Accessor for the entries.
857                 * @return entries.
858                 */
859                public AMemberValue[] getEntries() {
860                    return entries;
861                }
862    
863    
864                /**
865                 * Indicates whether some other object is "equal to" this one.
866                 * @param o the reference object with which to compare.
867                 * @return <code>true</code> if this object is the same as the obj argument; <code>false</code> otherwise.
868                 */
869                public boolean equals(Object o) {
870                    if (this == o) {
871                        return true;
872                    }
873                    if (o == null || getClass() != o.getClass()) {
874                        return false;
875                    }
876    
877                    ArrayMemberValue that = (ArrayMemberValue)o;
878    
879                    if (numEntries != that.numEntries) {
880                        return false;
881                    }
882                    if (!Arrays.equals(entries, that.entries)) {
883                        return false;
884                    }
885    
886                    return true;
887                }
888    
889                /**
890                 * Returns a hash code value for the object.
891                 * @return a hash code value for this object.
892                 */
893                public int hashCode() {
894                    int result;
895                    result = numEntries;
896                    result = 31 * result + (entries != null ? Arrays.hashCode(entries) : 0);
897                    return result;
898                }
899            }
900    
901            /**
902             * Storage class for a name-value pair.
903             */
904            public static class NameValuePair {
905                /**
906                 * Name.
907                 */
908                private AUTFPoolInfo name;
909    
910                /**
911                 * Value.
912                 */
913                private AMemberValue value;
914    
915                /**
916                 * Creates a new name-value pair.
917                 * @param name name
918                 * @param value value
919                 */
920                public NameValuePair(AUTFPoolInfo name, AMemberValue value) {
921                    this.name = name;
922                    this.value = value;
923                }
924    
925                /**
926                 * Creates a new name-value pair.
927                 * @param cp constant pool
928                 * @param data data array
929                 * @param start start index in array
930                 */
931                public NameValuePair(ConstantPool cp, byte[] data, int start) {
932                    name = cp.get(Types.ushortFromBytes(data, start + 0)).execute(CheckUTFVisitor.singleton(), null);
933                    value = Annotation.AMemberValue.read(cp, data, start + 2);
934                }
935    
936                /**
937                 * Returns the size of this name-value pair.
938                 * @return size in bytes
939                 */
940                public int getSize() {
941                    return 2 + value.getSize();
942                }
943    
944                /**
945                 * Writes this name-value pair into the stream.
946                 * @param cp constant pool
947                 * @param baos stream
948                 * @throws IOException
949                 */
950                public void writeToByteArrayOutputStream(ConstantPool cp, ByteArrayOutputStream baos) throws IOException {
951                    baos.write(Types.bytesFromShort(cp.indexOf(name)));
952                    value.writeToByteArrayOutputStream(cp, baos);
953                }
954    
955                /**
956                 * Returns a string representation of the object.
957                 * @return a string representation of the object.
958                 */
959                public String toString() {
960                    return name.toString() + " = " + value.toString();
961                }
962    
963                /**
964                 * Accessor for the name.
965                 * @return name name
966                 */
967                public AUTFPoolInfo getName() {
968                    return name;
969                }
970    
971                /**
972                 * Accessor for the value.
973                 * @return value
974                 */
975                public AMemberValue getValue() {
976                    return value;
977                }
978    
979    
980                /**
981                 * Indicates whether some other object is "equal to" this one.
982                 * @param o the reference object with which to compare.
983                 * @return <code>true</code> if this object is the same as the obj argument; <code>false</code> otherwise.
984                 */
985                public boolean equals(Object o) {
986                    if (this == o) {
987                        return true;
988                    }
989                    if (o == null || getClass() != o.getClass()) {
990                        return false;
991                    }
992    
993                    NameValuePair that = (NameValuePair)o;
994    
995                    if (name != null ? !name.equals(that.name) : that.name != null) {
996                        return false;
997                    }
998                    if (value != null ? !value.equals(that.value) : that.value != null) {
999                        return false;
1000                    }
1001    
1002                    return true;
1003                }
1004    
1005                /**
1006                 * Returns a hash code value for the object.
1007                 * @return a hash code value for this object.
1008                 */
1009                public int hashCode() {
1010                    int result;
1011                    result = (name != null ? name.hashCode() : 0);
1012                    result = 31 * result + (value != null ? value.hashCode() : 0);
1013                    return result;
1014                }
1015            }
1016    
1017            /**
1018             * Type name of annotation.
1019             */
1020            private AUTFPoolInfo _type;
1021    
1022            /**
1023             * Number of stored name-value _pairs.
1024             */
1025            private int _pairCount;
1026    
1027            /**
1028             * Name-value _pairs.
1029             */
1030            private NameValuePair[] _pairs;
1031    
1032            /**
1033             * Creates a new annotation.
1034             * @param type name of _type
1035             * @param pairCount number of name-value _pairs
1036             * @param pairs array of name-value _pairs
1037             */
1038            public Annotation(AUTFPoolInfo type,
1039                              short pairCount,
1040                              Annotation.NameValuePair[] pairs) {
1041                this._type = type;
1042                this._pairCount = pairCount;
1043                this._pairs = pairs;
1044            }
1045    
1046            /**
1047             * Creates a new annotation.
1048             * @param cp constant pool
1049             * @param data data array
1050             * @param start start index in data array
1051             */
1052            public Annotation(ConstantPool cp, byte[] data, int start) {
1053                _type = cp.get(Types.ushortFromBytes(data, start + 0)).execute(CheckUTFVisitor.singleton(), null);
1054                _pairCount = Types.ushortFromBytes(data, start + 2);
1055                _pairs = new Annotation.NameValuePair[_pairCount];
1056                int index = start + 4;
1057                for(int i=0; i<_pairCount; ++i) {
1058                    _pairs[i] = new Annotation.NameValuePair(cp, data, index);
1059                    index += _pairs[i].getSize();
1060                }
1061            }
1062    
1063            /**
1064             * Returns the size of this annotation.
1065             * @return size in bytes
1066             */
1067            public int getSize() {
1068                int accum = 4;
1069                for(Annotation.NameValuePair pair : _pairs) {
1070                    accum += pair.getSize();
1071                }
1072                return accum;
1073            }
1074    
1075            /**
1076             * Writes this annotation into the stream.
1077             * @param cp constant pool
1078             * @param baos stream
1079             * @throws IOException
1080             */
1081            public void writeToByteArrayOutputStream(ConstantPool cp, ByteArrayOutputStream baos) throws IOException {
1082                baos.write(Types.bytesFromShort(cp.indexOf(_type)));
1083                baos.write(Types.bytesFromShort((short)(_pairCount & 0xffff)));
1084                for(Annotation.NameValuePair nvp:_pairs) {
1085                    nvp.writeToByteArrayOutputStream(cp, baos);
1086                }
1087            }
1088    
1089            /**
1090             * Returns a string representation of the object.
1091             * @return a string representation of the object.
1092             */
1093            public String toString() {
1094                StringBuilder sb = new StringBuilder();
1095                sb.append("@");
1096                sb.append(_type.toString());
1097                if (_pairCount>0) {
1098                    sb.append("(");
1099                    boolean first = true;
1100                    for(NameValuePair nvp:_pairs) {
1101                        if (first) {
1102                            first = false;
1103                        }
1104                        else {
1105                            sb.append(", ");
1106                        }
1107                        sb.append(nvp.toString());
1108                    }
1109                    sb.append(")");
1110                }
1111                return sb.toString();
1112            }
1113    
1114            /**
1115             * Returns a string representation of the object like it would be seen in a Java listing.
1116             * @return a string representation of the object.
1117             */
1118            public String toStringJava() {
1119                StringBuilder sb = new StringBuilder();
1120                sb.append("@");
1121                String typeName = ClassFileTools.getTypeString(_type.toString(),"").replace('$','.');
1122                typeName = typeName.substring(0, typeName.length()-1);
1123                sb.append(typeName);
1124                if (_pairCount>0) {
1125                    sb.append("(");
1126                    boolean first = true;
1127                    for(NameValuePair nvp:_pairs) {
1128                        if (first) {
1129                            first = false;
1130                        }
1131                        else {
1132                            sb.append(", ");
1133                        }
1134                        sb.append(nvp.toString());
1135                    }
1136                    sb.append(")");
1137                }
1138                return sb.toString();
1139            }
1140    
1141            /**
1142             * Returns the type of the annotation.
1143             * @return _type string
1144             */
1145            public String getType() {
1146                return _type.toString();
1147            }
1148    
1149            /**
1150             * Returns a list of the pairs.
1151             * @return list of name-value pairs.
1152             */
1153            public List<NameValuePair> getPairs() {
1154                ArrayList<NameValuePair> list = new ArrayList<NameValuePair>();
1155                for(NameValuePair nvp: _pairs) {
1156                    list.add(nvp);
1157                }
1158                return list;
1159            }
1160    
1161            /**
1162             * Indicates whether some other object is "equal to" this one.
1163             * @param o the reference object with which to compare.
1164             * @return <code>true</code> if this object is the same as the obj argument; <code>false</code> otherwise.
1165             */
1166            public boolean equals(Object o) {
1167                if (this == o) {
1168                    return true;
1169                }
1170                if (o == null || getClass() != o.getClass()) {
1171                    return false;
1172                }
1173    
1174                Annotation that = (Annotation)o;
1175    
1176                if (_pairCount != that._pairCount) {
1177                    return false;
1178                }
1179                if (!Arrays.equals(_pairs, that._pairs)) {
1180                    return false;
1181                }
1182                if (_type != null ? !_type.equals(that._type) : that._type != null) {
1183                    return false;
1184                }
1185    
1186                return true;
1187            }
1188    
1189            /**
1190             * Returns a hash code value for the object.
1191             * @return a hash code value for this object.
1192             */
1193            public int hashCode() {
1194                int result;
1195                result = (_type != null ? _type.hashCode() : 0);
1196                result = 31 * result + _pairCount;
1197                result = 31 * result + (_pairs != null ? Arrays.hashCode(_pairs) : 0);
1198                return result;
1199            }
1200        }
1201    
1202        /**
1203         * Creates a new abstract annotations attribute.
1204         * @param name name of attribute
1205         * @param data data array
1206         * @param cp constant pool
1207         */
1208        public AAnnotationsAttributeInfo(AUTFPoolInfo name, byte data[], ConstantPool cp) {
1209            super(name, data, cp);
1210        }
1211    
1212        /**
1213         * Adjust program counter values contained in this attribute, starting at startPC, by adding deltaPC to them.
1214         *
1215         * @param startPC program counter to start at
1216         * @param deltaPC change in program counter values
1217         */
1218        public void adjustPC(int startPC, int deltaPC) {
1219            // nothing to do
1220        }
1221    
1222        /**
1223         * Translate the program counter values contained in this attribute from an old line number table to a new one.
1224         *
1225         * @param index      critical point (insertion or deletion point)
1226         * @param deltaIndex delta value to add to all old line numbers greater than the critical point
1227         * @param oldLnt     old line number table
1228         * @param newLnt     new line number table
1229         */
1230        public void translatePC(int index, int deltaIndex, LineNumberTable oldLnt, LineNumberTable newLnt) {
1231            // nothing to do
1232        }
1233    
1234        /**
1235         * Creates and returns a copy of this object.
1236         */
1237        public Object clone() throws CloneNotSupportedException {
1238            return super.clone();
1239        }
1240    }