001: /* ===========================================================================
002: * $RCSfile: AttrInfo.java,v $
003: * ===========================================================================
004: *
005: * RetroGuard -- an obfuscation package for Java classfiles.
006: *
007: * Copyright (c) 1998-2006 Mark Welsh (markw@retrologic.com)
008: *
009: * This program can be redistributed and/or modified under the terms of the
010: * Version 2 of the GNU General Public License as published by the Free
011: * Software Foundation.
012: *
013: * This program is distributed in the hope that it will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016: * GNU General Public License for more details.
017: *
018: */
019:
020: package COM.rl.obf.classfile;
021:
022: import java.io.*;
023: import java.util.*;
024:
025: /**
026: * Representation of an attribute. Specific attributes have their representations
027: * sub-classed from this.
028: *
029: * @author Mark Welsh
030: */
031: public class AttrInfo implements ClassConstants {
032: // Constants -------------------------------------------------------------
033: public static final int CONSTANT_FIELD_SIZE = 6;
034:
035: // Fields ----------------------------------------------------------------
036: private int u2attrNameIndex;
037: private int u4attrLength;
038: private byte info[];
039:
040: protected ClassFile cf;
041:
042: // Class Methods ---------------------------------------------------------
043: /**
044: * Create a new AttrInfo from the data passed.
045: *
046: * @throws IOException if class file is corrupt or incomplete
047: */
048: public static AttrInfo create(DataInput din, ClassFile cf)
049: throws Exception {
050: if (din == null)
051: throw new IOException("No input stream was provided.");
052:
053: // Instantiate based on attribute name
054: AttrInfo ai = null;
055: int attrNameIndex = din.readUnsignedShort();
056: int attrLength = din.readInt();
057: CpInfo cpInfo = cf.getCpEntry(attrNameIndex);
058: if (cpInfo instanceof Utf8CpInfo) {
059: String attrName = ((Utf8CpInfo) cpInfo).getString();
060: if (attrName.equals(ATTR_Code)) {
061: ai = new CodeAttrInfo(cf, attrNameIndex, attrLength);
062: } else if (attrName.equals(ATTR_ConstantValue)) {
063: ai = new ConstantValueAttrInfo(cf, attrNameIndex,
064: attrLength);
065: } else if (attrName.equals(ATTR_Exceptions)) {
066: ai = new ExceptionsAttrInfo(cf, attrNameIndex,
067: attrLength);
068: } else if (attrName.equals(ATTR_LineNumberTable)) {
069: ai = new LineNumberTableAttrInfo(cf, attrNameIndex,
070: attrLength);
071: } else if (attrName.equals(ATTR_SourceFile)) {
072: ai = new SourceFileAttrInfo(cf, attrNameIndex,
073: attrLength);
074: } else if (attrName.equals(ATTR_LocalVariableTable)) {
075: ai = new LocalVariableTableAttrInfo(cf, attrNameIndex,
076: attrLength);
077: } else if (attrName.equals(ATTR_InnerClasses)) {
078: ai = new InnerClassesAttrInfo(cf, attrNameIndex,
079: attrLength);
080: } else if (attrName.equals(ATTR_Synthetic)) {
081: ai = new SyntheticAttrInfo(cf, attrNameIndex,
082: attrLength);
083: } else if (attrName.equals(ATTR_Deprecated)) {
084: ai = new DeprecatedAttrInfo(cf, attrNameIndex,
085: attrLength);
086: } else if (attrName.equals(ATTR_Signature)) {
087: ai = new SignatureAttrInfo(cf, attrNameIndex,
088: attrLength);
089: } else if (attrName.equals(ATTR_LocalVariableTypeTable)) {
090: ai = new LocalVariableTypeTableAttrInfo(cf,
091: attrNameIndex, attrLength);
092: } else if (attrName.equals(ATTR_RuntimeVisibleAnnotations)) {
093: ai = new RuntimeVisibleAnnotationsAttrInfo(cf,
094: attrNameIndex, attrLength);
095: } else if (attrName
096: .equals(ATTR_RuntimeInvisibleAnnotations)) {
097: ai = new RuntimeInvisibleAnnotationsAttrInfo(cf,
098: attrNameIndex, attrLength);
099: } else if (attrName
100: .equals(ATTR_RuntimeVisibleParameterAnnotations)) {
101: ai = new RuntimeVisibleParameterAnnotationsAttrInfo(cf,
102: attrNameIndex, attrLength);
103: } else if (attrName
104: .equals(ATTR_RuntimeInvisibleParameterAnnotations)) {
105: ai = new RuntimeInvisibleParameterAnnotationsAttrInfo(
106: cf, attrNameIndex, attrLength);
107: } else if (attrName.equals(ATTR_AnnotationDefault)) {
108: ai = new AnnotationDefaultAttrInfo(cf, attrNameIndex,
109: attrLength);
110: } else if (attrName.equals(ATTR_EnclosingMethod)) {
111: ai = new EnclosingMethodAttrInfo(cf, attrNameIndex,
112: attrLength);
113: } else if (attrName.equals(ATTR_StackMapTable)) {
114: ai = new StackMapTableAttrInfo(cf, attrNameIndex,
115: attrLength);
116: } else {
117: ai = new AttrInfo(cf, attrNameIndex, attrLength);
118: }
119: } else {
120: throw new Exception(
121: "Inconsistent reference to Constant Pool.");
122: }
123: ai.readInfo(din);
124: return ai;
125: }
126:
127: // Instance Methods ------------------------------------------------------
128: protected AttrInfo(ClassFile cf, int attrNameIndex, int attrLength) {
129: this .cf = cf;
130: this .u2attrNameIndex = attrNameIndex;
131: this .u4attrLength = attrLength;
132: }
133:
134: /** Return the length in bytes of the attribute; over-ride this in sub-classes. */
135: protected int getAttrInfoLength() throws Exception {
136: return u4attrLength;
137: }
138:
139: /** Return the String name of the attribute; over-ride this in sub-classes. */
140: protected String getAttrName() throws Exception {
141: return ATTR_Unknown;
142: }
143:
144: /**
145: * Trim attributes from the classfile except those in the String[].
146: */
147: protected void trimAttrsExcept(String[] keepAttrs) throws Exception {
148: }
149:
150: /** Check for Utf8 references to constant pool and mark them. */
151: protected void markUtf8Refs(ConstantPool pool) throws Exception {
152: pool.incRefCount(u2attrNameIndex);
153: markUtf8RefsInInfo(pool);
154: }
155:
156: /**
157: * Check for Utf8 references in the 'info' data to the constant pool and
158: * mark them; over-ride this in sub-classes.
159: */
160: protected void markUtf8RefsInInfo(ConstantPool pool)
161: throws Exception {
162: }
163:
164: /** Read the data following the header; over-ride this in sub-classes. */
165: protected void readInfo(DataInput din) throws Exception {
166: info = new byte[u4attrLength];
167: din.readFully(info);
168: }
169:
170: /** Export the representation to a DataOutput stream. */
171: public final void write(DataOutput dout) throws Exception {
172: if (dout == null)
173: throw new IOException("No output stream was provided.");
174: dout.writeShort(u2attrNameIndex);
175: dout.writeInt(getAttrInfoLength());
176: writeInfo(dout);
177: }
178:
179: /** Export data following the header to a DataOutput stream; over-ride this in sub-classes. */
180: public void writeInfo(DataOutput dout) throws Exception {
181: dout.write(info);
182: }
183:
184: /** Do necessary name remapping. */
185: protected void remap(ClassFile cf, NameMapper nm) throws Exception {
186: }
187:
188: /** Provide debugging dump of this object. */
189: public void dump(PrintStream ps) throws Exception {
190: ps.println("u2attrNameIndex : " + u2attrNameIndex + " "
191: + cf.getUtf8(u2attrNameIndex));
192: ps.println("u4attrLength : " + u4attrLength);
193: }
194: }
|