Home | History | Annotate | Download | only in bytecode
      1 /*
      2  * Javassist, a Java-bytecode translator toolkit.
      3  * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved.
      4  *
      5  * The contents of this file are subject to the Mozilla Public License Version
      6  * 1.1 (the "License"); you may not use this file except in compliance with
      7  * the License.  Alternatively, the contents of this file may be used under
      8  * the terms of the GNU Lesser General Public License Version 2.1 or later.
      9  *
     10  * Software distributed under the License is distributed on an "AS IS" basis,
     11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
     12  * for the specific language governing rights and limitations under the
     13  * License.
     14  */
     15 
     16 package javassist.bytecode;
     17 
     18 import java.io.DataInputStream;
     19 import java.io.DataOutputStream;
     20 import java.io.IOException;
     21 import java.util.Map;
     22 import java.util.ArrayList;
     23 import java.util.ListIterator;
     24 import java.util.List;
     25 import java.util.Iterator;
     26 
     27 // Note: if you define a new subclass of AttributeInfo, then
     28 //       update AttributeInfo.read(), .copy(), and (maybe) write().
     29 
     30 /**
     31  * <code>attribute_info</code> structure.
     32  */
     33 public class AttributeInfo {
     34     protected ConstPool constPool;
     35     int name;
     36     byte[] info;
     37 
     38     protected AttributeInfo(ConstPool cp, int attrname, byte[] attrinfo) {
     39         constPool = cp;
     40         name = attrname;
     41         info = attrinfo;
     42     }
     43 
     44     protected AttributeInfo(ConstPool cp, String attrname) {
     45         this(cp, attrname, (byte[])null);
     46     }
     47 
     48     /**
     49      * Constructs an <code>attribute_info</code> structure.
     50      *
     51      * @param cp                constant pool table
     52      * @param attrname          attribute name
     53      * @param attrinfo          <code>info</code> field
     54      *                          of <code>attribute_info</code> structure.
     55      */
     56     public AttributeInfo(ConstPool cp, String attrname, byte[] attrinfo) {
     57         this(cp, cp.addUtf8Info(attrname), attrinfo);
     58     }
     59 
     60     protected AttributeInfo(ConstPool cp, int n, DataInputStream in)
     61         throws IOException
     62     {
     63         constPool = cp;
     64         name = n;
     65         int len = in.readInt();
     66         info = new byte[len];
     67         if (len > 0)
     68             in.readFully(info);
     69     }
     70 
     71     static AttributeInfo read(ConstPool cp, DataInputStream in)
     72         throws IOException
     73     {
     74         int name = in.readUnsignedShort();
     75         String nameStr = cp.getUtf8Info(name);
     76         if (nameStr.charAt(0) < 'L') {
     77             if (nameStr.equals(AnnotationDefaultAttribute.tag))
     78                 return new AnnotationDefaultAttribute(cp, name, in);
     79             else if (nameStr.equals(CodeAttribute.tag))
     80                 return new CodeAttribute(cp, name, in);
     81             else if (nameStr.equals(ConstantAttribute.tag))
     82                 return new ConstantAttribute(cp, name, in);
     83             else if (nameStr.equals(DeprecatedAttribute.tag))
     84                 return new DeprecatedAttribute(cp, name, in);
     85             else if (nameStr.equals(EnclosingMethodAttribute.tag))
     86                 return new EnclosingMethodAttribute(cp, name, in);
     87             else if (nameStr.equals(ExceptionsAttribute.tag))
     88                 return new ExceptionsAttribute(cp, name, in);
     89             else if (nameStr.equals(InnerClassesAttribute.tag))
     90                 return new InnerClassesAttribute(cp, name, in);
     91         }
     92         else {
     93             /* Note that the names of Annotations attributes begin with 'R'.
     94              */
     95             if (nameStr.equals(LineNumberAttribute.tag))
     96                 return new LineNumberAttribute(cp, name, in);
     97             else if (nameStr.equals(LocalVariableAttribute.tag))
     98                 return new LocalVariableAttribute(cp, name, in);
     99             else if (nameStr.equals(LocalVariableTypeAttribute.tag))
    100                 return new LocalVariableTypeAttribute(cp, name, in);
    101             else if (nameStr.equals(AnnotationsAttribute.visibleTag)
    102                      || nameStr.equals(AnnotationsAttribute.invisibleTag)) {
    103                 // RuntimeVisibleAnnotations or RuntimeInvisibleAnnotations
    104                 return new AnnotationsAttribute(cp, name, in);
    105             }
    106             else if (nameStr.equals(ParameterAnnotationsAttribute.visibleTag)
    107                 || nameStr.equals(ParameterAnnotationsAttribute.invisibleTag))
    108                 return new ParameterAnnotationsAttribute(cp, name, in);
    109             else if (nameStr.equals(SignatureAttribute.tag))
    110                 return new SignatureAttribute(cp, name, in);
    111             else if (nameStr.equals(SourceFileAttribute.tag))
    112                 return new SourceFileAttribute(cp, name, in);
    113             else if (nameStr.equals(SyntheticAttribute.tag))
    114                 return new SyntheticAttribute(cp, name, in);
    115             else if (nameStr.equals(StackMap.tag))
    116                 return new StackMap(cp, name, in);
    117             else if (nameStr.equals(StackMapTable.tag))
    118                 return new StackMapTable(cp, name, in);
    119         }
    120 
    121         return new AttributeInfo(cp, name, in);
    122     }
    123 
    124     /**
    125      * Returns an attribute name.
    126      */
    127     public String getName() {
    128         return constPool.getUtf8Info(name);
    129     }
    130 
    131     /**
    132      * Returns a constant pool table.
    133      */
    134     public ConstPool getConstPool() { return constPool; }
    135 
    136     /**
    137      * Returns the length of this <code>attribute_info</code>
    138      * structure.
    139      * The returned value is <code>attribute_length + 6</code>.
    140      */
    141     public int length() {
    142         return info.length + 6;
    143     }
    144 
    145     /**
    146      * Returns the <code>info</code> field
    147      * of this <code>attribute_info</code> structure.
    148      *
    149      * <p>This method is not available if the object is an instance
    150      * of <code>CodeAttribute</code>.
    151      */
    152     public byte[] get() { return info; }
    153 
    154     /**
    155      * Sets the <code>info</code> field
    156      * of this <code>attribute_info</code> structure.
    157      *
    158      * <p>This method is not available if the object is an instance
    159      * of <code>CodeAttribute</code>.
    160      */
    161     public void set(byte[] newinfo) { info = newinfo; }
    162 
    163     /**
    164      * Makes a copy.  Class names are replaced according to the
    165      * given <code>Map</code> object.
    166      *
    167      * @param newCp     the constant pool table used by the new copy.
    168      * @param classnames        pairs of replaced and substituted
    169      *                          class names.
    170      */
    171     public AttributeInfo copy(ConstPool newCp, Map classnames) {
    172         int s = info.length;
    173         byte[] srcInfo = info;
    174         byte[] newInfo = new byte[s];
    175         for (int i = 0; i < s; ++i)
    176             newInfo[i] = srcInfo[i];
    177 
    178         return new AttributeInfo(newCp, getName(), newInfo);
    179     }
    180 
    181     void write(DataOutputStream out) throws IOException {
    182         out.writeShort(name);
    183         out.writeInt(info.length);
    184         if (info.length > 0)
    185             out.write(info);
    186     }
    187 
    188     static int getLength(ArrayList list) {
    189         int size = 0;
    190         int n = list.size();
    191         for (int i = 0; i < n; ++i) {
    192             AttributeInfo attr = (AttributeInfo)list.get(i);
    193             size += attr.length();
    194         }
    195 
    196         return size;
    197     }
    198 
    199     static AttributeInfo lookup(ArrayList list, String name) {
    200         if (list == null)
    201             return null;
    202 
    203         ListIterator iterator = list.listIterator();
    204         while (iterator.hasNext()) {
    205             AttributeInfo ai = (AttributeInfo)iterator.next();
    206             if (ai.getName().equals(name))
    207                 return ai;
    208         }
    209 
    210         return null;            // no such attribute
    211     }
    212 
    213     static synchronized void remove(ArrayList list, String name) {
    214         if (list == null)
    215             return;
    216 
    217         ListIterator iterator = list.listIterator();
    218         while (iterator.hasNext()) {
    219             AttributeInfo ai = (AttributeInfo)iterator.next();
    220             if (ai.getName().equals(name))
    221                 iterator.remove();
    222         }
    223     }
    224 
    225     static void writeAll(ArrayList list, DataOutputStream out)
    226         throws IOException
    227     {
    228         if (list == null)
    229             return;
    230 
    231         int n = list.size();
    232         for (int i = 0; i < n; ++i) {
    233             AttributeInfo attr = (AttributeInfo)list.get(i);
    234             attr.write(out);
    235         }
    236     }
    237 
    238     static ArrayList copyAll(ArrayList list, ConstPool cp) {
    239         if (list == null)
    240             return null;
    241 
    242         ArrayList newList = new ArrayList();
    243         int n = list.size();
    244         for (int i = 0; i < n; ++i) {
    245             AttributeInfo attr = (AttributeInfo)list.get(i);
    246             newList.add(attr.copy(cp, null));
    247         }
    248 
    249         return newList;
    250     }
    251 
    252     /* The following two methods are used to implement
    253      * ClassFile.renameClass().
    254      * Only CodeAttribute, LocalVariableAttribute,
    255      * AnnotationsAttribute, and SignatureAttribute
    256      * override these methods.
    257      */
    258     void renameClass(String oldname, String newname) {}
    259     void renameClass(Map classnames) {}
    260 
    261     static void renameClass(List attributes, String oldname, String newname) {
    262         Iterator iterator = attributes.iterator();
    263         while (iterator.hasNext()) {
    264             AttributeInfo ai = (AttributeInfo)iterator.next();
    265             ai.renameClass(oldname, newname);
    266         }
    267     }
    268 
    269     static void renameClass(List attributes, Map classnames) {
    270         Iterator iterator = attributes.iterator();
    271         while (iterator.hasNext()) {
    272             AttributeInfo ai = (AttributeInfo)iterator.next();
    273             ai.renameClass(classnames);
    274         }
    275     }
    276 
    277     void getRefClasses(Map classnames) {}
    278 
    279     static void getRefClasses(List attributes, Map classnames) {
    280         Iterator iterator = attributes.iterator();
    281         while (iterator.hasNext()) {
    282             AttributeInfo ai = (AttributeInfo)iterator.next();
    283             ai.getRefClasses(classnames);
    284         }
    285     }
    286 }
    287