001: /*
002: This library is free software; you can redistribute it and/or
003: modify it under the terms of the GNU General Public
004: License as published by the Free Software Foundation; either
005: version 2 of the license, or (at your option) any later version.
006: */
007: package org.gjt.jclasslib.structures;
008:
009: import org.gjt.jclasslib.structures.attributes.*;
010: import org.gjt.jclasslib.structures.constants.ConstantUtf8Info;
011:
012: import java.io.*;
013:
014: /**
015: * Base class for all attribute structures in the <tt>attribute</tt> package.
016: *
017: * @author <a href="mailto:jclasslib@ej-technologies.com">Ingo Kegel</a>, <a href="mailto:vitor.carreira@gmail.com">Vitor Carreira</a>
018: * @version $Revision: 1.6 $ $Date: 2004/12/28 13:04:32 $
019: */
020: public class AttributeInfo extends AbstractStructureWithAttributes {
021:
022: /**
023: * Set this JVM System property to true to skip reading of all attributes.
024: * Some class file operations may fail in this case.
025: */
026: public static final String SYSTEM_PROPERTY_SKIP_ATTRIBUTES = "jclasslib.io.skipAttributes";
027:
028: private int attributeNameIndex;
029: private int attributeLength;
030: private byte[] info;
031:
032: /**
033: * Factory method for creating <tt>AttributeInfo</tt> structures. <p>
034: * An <tt>AttributeInfo</tt> of the appropriate subtype from the <tt>attributes</tt> package
035: * is created unless the type of the attribute is unknown in which case an instance of
036: * <tt>AttributeInfo</tt> is returned. <p>
037: * <p/>
038: * Attributes are skipped if the environment variable <tt>SYSTEM_PROPERTY_SKIP_ATTRIBUTES</tt>
039: * is set to true.
040: *
041: * @param in the <tt>DataInput</tt> from which to read the <tt>AttributeInfo</tt> structure
042: * @param classFile the parent class file of the structure to be created
043: * @return the new <tt>AttributeInfo</tt> structure
044: * @throws InvalidByteCodeException if the byte code is invalid
045: * @throws IOException if an exception occurs with the <tt>DataInput</tt>
046: */
047: public static AttributeInfo createOrSkip(DataInput in,
048: ClassFile classFile) throws InvalidByteCodeException,
049: IOException {
050:
051: AttributeInfo attributeInfo = null;
052:
053: if (Boolean.getBoolean(SYSTEM_PROPERTY_SKIP_ATTRIBUTES)) {
054: in.skipBytes(2);
055: in.skipBytes(in.readInt());
056: } else {
057: int attributeNameIndex = in.readUnsignedShort();
058: int attributeLength = in.readInt();
059:
060: ConstantUtf8Info cpInfoName = classFile
061: .getConstantPoolUtf8Entry(attributeNameIndex);
062: String attributeName = null;
063:
064: if (cpInfoName == null) {
065: return null;
066: }
067:
068: attributeName = cpInfoName.getString();
069:
070: if (ConstantValueAttribute.ATTRIBUTE_NAME
071: .equals(attributeName)) {
072: attributeInfo = new ConstantValueAttribute();
073:
074: } else if (CodeAttribute.ATTRIBUTE_NAME
075: .equals(attributeName)) {
076: attributeInfo = new CodeAttribute();
077:
078: } else if (ExceptionsAttribute.ATTRIBUTE_NAME
079: .equals(attributeName)) {
080: attributeInfo = new ExceptionsAttribute();
081:
082: } else if (InnerClassesAttribute.ATTRIBUTE_NAME
083: .equals(attributeName)) {
084: attributeInfo = new InnerClassesAttribute();
085:
086: } else if (SyntheticAttribute.ATTRIBUTE_NAME
087: .equals(attributeName)) {
088: attributeInfo = new SyntheticAttribute();
089:
090: } else if (SourceFileAttribute.ATTRIBUTE_NAME
091: .equals(attributeName)) {
092: attributeInfo = new SourceFileAttribute();
093:
094: } else if (LineNumberTableAttribute.ATTRIBUTE_NAME
095: .equals(attributeName)) {
096: attributeInfo = new LineNumberTableAttribute();
097:
098: } else if (LocalVariableTableAttribute.ATTRIBUTE_NAME
099: .equals(attributeName)) {
100: attributeInfo = new LocalVariableTableAttribute();
101:
102: } else if (DeprecatedAttribute.ATTRIBUTE_NAME
103: .equals(attributeName)) {
104: attributeInfo = new DeprecatedAttribute();
105:
106: } else if (EnclosingMethodAttribute.ATTRIBUTE_NAME
107: .equals(attributeName)) {
108: attributeInfo = new EnclosingMethodAttribute();
109:
110: } else if (SignatureAttribute.ATTRIBUTE_NAME
111: .equals(attributeName)) {
112: attributeInfo = new SignatureAttribute();
113:
114: } else if (LocalVariableTypeTableAttribute.ATTRIBUTE_NAME
115: .equals(attributeName)) {
116: attributeInfo = new LocalVariableTypeTableAttribute();
117:
118: } else if (RuntimeVisibleAnnotationsAttribute.ATTRIBUTE_NAME
119: .equals(attributeName)) {
120: attributeInfo = new RuntimeVisibleAnnotationsAttribute();
121:
122: } else if (RuntimeInvisibleAnnotationsAttribute.ATTRIBUTE_NAME
123: .equals(attributeName)) {
124: attributeInfo = new RuntimeInvisibleAnnotationsAttribute();
125:
126: } else if (AnnotationDefaultAttribute.ATTRIBUTE_NAME
127: .equals(attributeName)) {
128: attributeInfo = new AnnotationDefaultAttribute();
129:
130: } else {
131: attributeInfo = new AttributeInfo(attributeLength);
132: }
133: attributeInfo.setAttributeNameIndex(attributeNameIndex);
134: attributeInfo.setClassFile(classFile);
135: attributeInfo.read(in);
136: }
137:
138: return attributeInfo;
139: }
140:
141: /**
142: * Constructor.
143: */
144: protected AttributeInfo() {
145: }
146:
147: private AttributeInfo(int attributeLength) {
148: this .attributeLength = attributeLength;
149: }
150:
151: /**
152: * Get the constant pool index for the name of the attribute.
153: *
154: * @return the index
155: */
156: public int getAttributeNameIndex() {
157: return attributeNameIndex;
158: }
159:
160: /**
161: * Set the constant pool index for the name of the attribute.
162: *
163: * @param attributeNameIndex the new index
164: */
165: public void setAttributeNameIndex(int attributeNameIndex) {
166: this .attributeNameIndex = attributeNameIndex;
167: }
168:
169: /**
170: * Get the raw bytes of the attribute. <p>
171: * <p/>
172: * Is non-null only if attribute is of unknown type.
173: *
174: * @return the byte array
175: */
176: public byte[] getInfo() {
177: return info;
178: }
179:
180: /**
181: * Set the raw bytes of the attribute. <p>
182: * <p/>
183: * Works only if attribute is an instance of <tt>AttributeInfo</tt>.
184: *
185: * @param info the new byte array
186: */
187: public void setInfo(byte[] info) {
188: this .info = info;
189: }
190:
191: /**
192: * Get the name of the attribute.
193: *
194: * @return the name
195: * @throws InvalidByteCodeException if the byte code is invalid
196: */
197: public String getName() throws InvalidByteCodeException {
198: return classFile.getConstantPoolUtf8Entry(attributeNameIndex)
199: .getString();
200: }
201:
202: public void read(DataInput in) throws InvalidByteCodeException,
203: IOException {
204:
205: info = new byte[attributeLength];
206: in.readFully(info);
207:
208: if (debug)
209: debug("read " + getDebugMessage());
210: }
211:
212: public void write(DataOutput out) throws InvalidByteCodeException,
213: IOException {
214:
215: out.writeShort(attributeNameIndex);
216: out.writeInt(getAttributeLength());
217: if (getClass().equals(AttributeInfo.class)) {
218: out.write(info);
219: if (debug)
220: debug("wrote " + getDebugMessage());
221: }
222: }
223:
224: /**
225: * Get the length of this attribute as a number of bytes.
226: *
227: * @return the length
228: */
229: public int getAttributeLength() {
230: return getLength(info);
231: }
232:
233: // cannot override debug because subclasses will call super.debug
234: // and expect to call the implementation in AbstractStructure
235: private String getDebugMessage() {
236: String type;
237: try {
238: type = classFile.getConstantPoolUtf8Entry(
239: attributeNameIndex).getString();
240: } catch (InvalidByteCodeException ex) {
241: type = "(unknown)";
242: }
243:
244: return "uninterpreted attribute of reported type " + type;
245: }
246:
247: protected String printAccessFlagsVerbose(int accessFlags) {
248: if (accessFlags != 0)
249: throw new RuntimeException("Access flags should be zero: "
250: + Integer.toHexString(accessFlags));
251: return "";
252: }
253:
254: }
|