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.visitors.CheckUTFVisitor;
006    import edu.rice.cs.cunit.classFile.code.instructions.LineNumberTable;
007    import edu.rice.cs.cunit.util.Types;
008    
009    import java.io.ByteArrayOutputStream;
010    import java.io.IOException;
011    
012    /**
013     * @author Mathias Ricken
014     */
015    public abstract class AMultipleNamedAnnotationsAttributeInfo extends AAnnotationsAttributeInfo {
016        /**
017         * Storage class for name and annotations.
018         */
019        public static class NamedAnnotationsRecord {
020            private final AUTFPoolInfo name;
021            private final AAnnotationsAttributeInfo.Annotation[] annotations;
022    
023            public NamedAnnotationsRecord(AUTFPoolInfo name,
024                                                  AAnnotationsAttributeInfo.Annotation[] annotations) {
025                this.name = name;
026                this.annotations = new AAnnotationsAttributeInfo.Annotation[annotations.length];
027                System.arraycopy(annotations,0,this.annotations,0,annotations.length);
028            }
029    
030            public AUTFPoolInfo getName() {
031                return name;
032            }
033    
034            public Annotation[] getAnnotations() {
035                AAnnotationsAttributeInfo.Annotation[] as = new AAnnotationsAttributeInfo.Annotation[annotations.length];
036                System.arraycopy(annotations,0,as,0,annotations.length);
037                return as;
038            }
039        }
040    
041        public AMultipleNamedAnnotationsAttributeInfo(AUTFPoolInfo name, byte data[], ConstantPool cp) {
042            super(name, data, cp);
043        }
044    
045        /**
046         * Return the number of entities.
047         *
048         * @return number of entities
049         *
050         * @throws ClassFormatError
051         */
052        public int getEntityCount() {
053            return _data[0];
054        }
055    
056        /**
057         * Return an array of entity annotations records.
058         *
059         * @return array of entity annotations records.
060         *
061         * @throws ClassFormatError if the attribute has an incorrect format
062         */
063        public NamedAnnotationsRecord[] getEntityAnnotations() throws ClassFormatError {
064            int count = getEntityCount();
065            NamedAnnotationsRecord[] nar = new NamedAnnotationsRecord[count];
066            int index = 1;
067            for(int i = 0; i < count; ++i) {
068                AUTFPoolInfo name = _constantPool.get(Types.ushortFromBytes(_data, index+0)).execute(CheckUTFVisitor.singleton(), null);
069                short annCount = (short)(0xffff & Types.ushortFromBytes(_data, index+2));
070    
071                index += 4;
072    
073                AAnnotationsAttributeInfo.Annotation[] ann = new AAnnotationsAttributeInfo.Annotation[annCount];
074                for(short annIndex = 0; annIndex < annCount; ++annIndex) {
075                    ann[annIndex] = new AAnnotationsAttributeInfo.Annotation(_constantPool,_data,index);
076                    index += ann[annIndex].getSize();
077                }
078    
079                nar[i] = new NamedAnnotationsRecord(name, ann);
080            }
081            return nar;
082        }
083    
084        /**
085         * Set the array of entity annotations records.
086         *
087         * @param nars array of entity annotations records
088         */
089        public void setLocalVariableAnnotations(NamedAnnotationsRecord[] nars) {
090            ByteArrayOutputStream baos = new ByteArrayOutputStream();
091            baos.write((byte)nars.length);
092            for(NamedAnnotationsRecord r: nars) {
093                byte[] header = new byte[10];
094                Types.bytesFromShort((short)(0xffff & _constantPool.indexOf(r.name)), header, 0);
095                Types.bytesFromShort((short)(0xffff & r.annotations.length), header, 2);
096                baos.write(header, 0, 4);
097                for(int i = 0; i < r.annotations.length; ++i) {
098                    try {
099                        r.annotations[i].writeToByteArrayOutputStream(_constantPool,baos);
100                    }
101                    catch(IOException e) {
102                        throw new ClassFormatError("Error while writing out annotations");
103                    }
104                }
105            }
106            setData(baos.toByteArray());
107        }
108    
109        /**
110         * Return a human-readable version of this attribute.
111         *
112         * @return string
113         */
114        public String toString() {
115            StringBuilder x = new StringBuilder();
116            x.append(_name);
117            x.append(" <");
118            x.append(getEntityCount());
119            x.append(' ');
120            x.append(getEntityName());
121            x.append("(s) { ");
122            boolean first = true;
123            for(NamedAnnotationsRecord nars : getEntityAnnotations()) {
124                if (first) {
125                    first = false;
126                }
127                else {
128                    x.append(", ");
129                }
130                x.append("(name=");
131                x.append(nars.name.toString());
132                x.append(", annotations ");
133                x.append(nars.annotations.length);
134                x.append(": {");
135    
136                boolean firstAnn = true;
137                for(AAnnotationsAttributeInfo.Annotation ann : nars.annotations) {
138                    if (firstAnn) {
139                        firstAnn = false;
140                    }
141                    else {
142                        x.append(", ");
143                    }
144                    x.append(ann.toString());
145                }
146                x.append(" }");
147            }
148            x.append(" } >");
149            return x.toString();
150        }
151    
152        /**
153         * Return the name of the entity, e.g. "parameter" or "local variable".
154         * @return name of tne entity
155         */
156        public abstract String getEntityName();
157    
158        /**
159         * Adjust program counter values contained in this attribute, starting at startPC, by adding deltaPC to them.
160         *
161         * @param startPC program counter to start at
162         * @param deltaPC change in program counter values
163         */
164        public void adjustPC(int startPC, int deltaPC) {
165            // nothing to do
166        }
167    
168        /**
169         * Translate the program counter values contained in this attribute from an old line number table to a new one.
170         *
171         * @param index      critical point (insertion or deletion point)
172         * @param deltaIndex delta value to add to all old line numbers greater than the critical point
173         * @param oldLnt     old line number table
174         * @param newLnt     new line number table
175         */
176        public void translatePC(int index, int deltaIndex, LineNumberTable oldLnt, LineNumberTable newLnt) {
177            // nothing to do
178        }
179    
180        /**
181         * Creates and returns a copy of this object.
182         */
183        public Object clone() throws CloneNotSupportedException {
184            return super.clone();
185        }
186    }