1/* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved.
2 *
3 * This program and the accompanying materials are made available under
4 * the terms of the Common Public License v1.0 which accompanies this distribution,
5 * and is available at http://www.eclipse.org/legal/cpl-v10.html
6 *
7 * $Id: Attribute_info.java,v 1.1.1.1 2004/05/09 16:57:47 vlad_r Exp $
8 */
9package com.vladium.jcd.cls.attribute;
10
11import java.io.IOException;
12
13import com.vladium.jcd.cls.ClassDef;
14import com.vladium.jcd.cls.IConstantCollection;
15import com.vladium.jcd.cls.constant.*;
16import com.vladium.jcd.compiler.IClassFormatOutput;
17import com.vladium.jcd.lib.UDataInputStream;
18import com.vladium.jcd.lib.UDataOutputStream;
19
20// ----------------------------------------------------------------------------
21/**
22 * Abstract base for all XXXAttribute_info structures. It also works in conjunction
23 * with {@link GenericAttribute_info} class to process all unrecognized attributes.<P>
24 *
25 * Attributes are used in the {@link com.vladium.jcd.cls.ClassDef}, {@link com.vladium.jcd.cls.Field_info},
26 * {@link com.vladium.jcd.cls.Method_info}, and {@link CodeAttribute_info}
27 * structures of the .class file format. All attributes have the following
28 * general format:
29 * <PRE>
30 *  attribute_info {
31 *          u2 attribute_name_index;
32 *          u4 attribute_length;
33 *          u1 info[attribute_length];
34 *  }
35 * </PRE>
36 *
37 * For all attributes, the attribute_name_index must be a valid unsigned 16-bit
38 * index into the constant pool of the class. The constant pool entry at
39 * attribute_name_index must be a {@link com.vladium.jcd.cls.constant.CONSTANT_Utf8_info}
40 * string representing the name of the attribute. The value of the attribute_length
41 * item indicates the length of the subsequent information in bytes. The length
42 * does not include the initial six bytes that contain the attribute_name_index
43 * and attribute_length items.
44 *
45 * @see GenericAttribute_info
46 *
47 * @author (C) 2001, Vlad Roubtsov
48 */
49public
50abstract class Attribute_info implements Cloneable, IClassFormatOutput
51{
52    // public: ................................................................
53
54    public static final String ATTRIBUTE_CODE               = "Code";
55    public static final String ATTRIBUTE_CONSTANT_VALUE     = "ConstantValue";
56    public static final String ATTRIBUTE_LINE_NUMBER_TABLE  = "LineNumberTable";
57    public static final String ATTRIBUTE_EXCEPTIONS         = "Exceptions";
58    public static final String ATTRIBUTE_SYNTHETIC          = "Synthetic";
59    public static final String ATTRIBUTE_BRIDGE             = "Bridge";
60    public static final String ATTRIBUTE_SOURCEFILE         = "SourceFile";
61    public static final String ATTRIBUTE_INNERCLASSES       = "InnerClasses";
62
63    /**
64     * Constant pool index for {@link com.vladium.jcd.cls.constant.CONSTANT_Utf8_info}
65     * string representing the name of this attribute [always positive].
66     */
67    public int m_name_index;
68
69    /**
70     * Returns the name for this attribute within the constant pool context of 'cls'
71     * class definition.
72     *
73     * @param cls class that contains this attribute
74     * @return attribute name
75     */
76    public String getName (final ClassDef cls)
77    {
78        return ((CONSTANT_Utf8_info) cls.getConstants ().get (m_name_index)).m_value;
79    }
80
81    /**
82     * Returns the total length of this attribute when converted to
83     * .class format [including the 6-byte header]
84     */
85    public abstract long length (); // including the 6-byte header
86
87    // Visitor:
88
89    public abstract void accept (IAttributeVisitor visitor, Object ctx);
90
91    public abstract String toString ();
92
93    // TODO: use a hashmap lookup in this method + control which set of attrs get mapped to generic
94    /**
95     * Parses out a single Attribute_info element out of .class data in
96     * 'bytes'.
97     *
98     * @param constants constant pool for the parent class [may not be null; not validated]
99     * @param bytes input .class data stream [may not be null; not validated]
100     *
101     * @return a single parsed attribute
102     *
103     * @throws IOException on input errors
104     */
105    public static Attribute_info new_Attribute_info (final IConstantCollection constants,
106                                                     final UDataInputStream bytes)
107        throws IOException
108    {
109        final int attribute_name_index = bytes.readU2 ();
110        final long attribute_length = bytes.readU4 ();
111
112        final CONSTANT_Utf8_info attribute_name = (CONSTANT_Utf8_info) constants.get (attribute_name_index);
113        final String name = attribute_name.m_value;
114
115        if (ATTRIBUTE_CODE.equals (name))
116        {
117            return new CodeAttribute_info (constants, attribute_name_index, attribute_length, bytes);
118        }
119        else if (ATTRIBUTE_CONSTANT_VALUE.equals (name))
120        {
121            return new ConstantValueAttribute_info (attribute_name_index, attribute_length, bytes);
122        }
123        else if (ATTRIBUTE_EXCEPTIONS.equals (name))
124        {
125            return new ExceptionsAttribute_info (attribute_name_index, attribute_length, bytes);
126        }
127        else if (ATTRIBUTE_INNERCLASSES.equals (name))
128        {
129            return new InnerClassesAttribute_info (attribute_name_index, attribute_length, bytes);
130        }
131        else if (ATTRIBUTE_SYNTHETIC.equals (name))
132        {
133            return new SyntheticAttribute_info (attribute_name_index, attribute_length);
134        }
135        else if (ATTRIBUTE_BRIDGE.equals (name))
136        {
137            return new BridgeAttribute_info (attribute_name_index, attribute_length);
138        }
139        else if (ATTRIBUTE_LINE_NUMBER_TABLE.equals (name))
140        {
141            return new LineNumberTableAttribute_info (attribute_name_index, attribute_length, bytes);
142        }
143        else if (ATTRIBUTE_SOURCEFILE.equals (name))
144        {
145            return new SourceFileAttribute_info (attribute_name_index, attribute_length, bytes);
146        }
147        else
148        {
149            // default:
150            return new GenericAttribute_info (attribute_name_index, attribute_length, bytes);
151        }
152    }
153
154    // Cloneable:
155
156    /**
157     * Chains to super.clone() and removes CloneNotSupportedException
158     * from the method signature.
159     */
160    public Object clone ()
161    {
162        try
163        {
164            return super.clone ();
165        }
166        catch (CloneNotSupportedException e)
167        {
168            throw new InternalError (e.toString ());
169        }
170    }
171
172    // IClassFormatOutput:
173
174    public void writeInClassFormat (UDataOutputStream out) throws IOException
175    {
176        out.writeU2 (m_name_index);
177        out.writeU4 (length () - 6); // don't use m_attribute_length
178    }
179
180    // protected: .............................................................
181
182    /*
183    protected Attribute_info (UDataInputStream bytes) throws IOException
184    {
185        //m_name_index = bytes.readU2 ();
186        //m_attribute_length = bytes.readU4 ();
187    }
188    */
189
190    protected Attribute_info (final int attribute_name_index, final long attribute_length)
191    {
192        m_name_index = attribute_name_index;
193        m_attribute_length = attribute_length;
194    }
195
196    // TODO: remove this field as it is invalidated easily by most attribute mutations
197    protected long m_attribute_length; // excluding the 6-byte header
198
199    // package: ...............................................................
200
201    // private: ...............................................................
202
203} // end of class
204// ----------------------------------------------------------------------------
205