001: // Copyright (c) 1997 Per M.A. Bothner.
002: // This is free software; for terms and warranty disclaimer see ./COPYING.
003:
004: package gnu.bytecode;
005:
006: import java.io.*;
007:
008: /**
009: * Represents an Attribute of an AttrContainer.
010: * <p>
011: * Various sub-classses are used for standard attributes,
012: * or you can use MiscAttr for a generic attribute.
013: * @author Per Bothner
014: */
015:
016: public abstract class Attribute {
017: /** Every Attribute belongs to some AttrContainer object. */
018: AttrContainer container;
019:
020: /** Return the Attribute container that contains this Attribute. */
021: public final AttrContainer getContainer() {
022: return container;
023: }
024:
025: public final void setContainer(AttrContainer container) {
026: this .container = container;
027: }
028:
029: Attribute next;
030:
031: /** Get the next Attribute belonging to getContainer(). */
032: public final Attribute getNext() {
033: return next;
034: }
035:
036: /** Set the next Attribute in the chain belonging to getContainer(). */
037: public final void setNext(Attribute next) {
038: this .next = next;
039: }
040:
041: /** Add this to (the front of) of the specified attribute container. */
042: public void addToFrontOf(AttrContainer container) {
043: setContainer(container);
044: setNext(container.getAttributes());
045: container.setAttributes(this );
046: }
047:
048: String name; // This is an interned string.
049:
050: // If > 0, the constant-pool index of name.
051: // If -1, means attribute should be skipped on output.
052: int name_index;
053:
054: /** Returns true if this attribute should be skipped on output. */
055: public final boolean isSkipped() {
056: return name_index < 0;
057: }
058:
059: /** Iff skip, cause this attributed to be skipped on output. */
060: public final void setSkipped(boolean skip) {
061: name_index = skip ? -1 : 0;
062: }
063:
064: /** Cause this attributed to be skipped on output. */
065: public final void setSkipped() {
066: name_index = -1;
067: }
068:
069: public final String getName() {
070: return name;
071: }
072:
073: public final void setName(String name) {
074: this .name = name.intern();
075: }
076:
077: public final int getNameIndex() {
078: return name_index;
079: }
080:
081: public final void setNameIndex(int index) {
082: name_index = index;
083: }
084:
085: /** Create a new Attribute.
086: * @param name - an interned String that names the Attribute. */
087: public Attribute(String name) {
088: this .name = name;
089: }
090:
091: /** Find an Attribute by name, in an attribute cointainer.
092: * @param container the attribute container to search
093: * @param name the (interned) name of the attribute we are seeking
094: * @return the matching Attribute, or null if the search failed.
095: */
096: public static Attribute get(AttrContainer container, String name) {
097: for (Attribute attr = container.getAttributes(); attr != null; attr = attr.next) {
098: if (attr.getName() == name)
099: return attr;
100: }
101: return null;
102: }
103:
104: /** Add any needed constant pool entries for this Attribute.
105: * Overridden by sub-classes.
106: * Do any other cleanup needed before writing out a .class file. */
107: public void assignConstants(ClassType cl) {
108: if (name_index == 0)
109: name_index = cl.getConstants().addUtf8(name).getIndex();
110: }
111:
112: /** Add any needed constant pool entries for all attributes in a container.
113: * Do any other cleanup needed before writing out a .class file. */
114: public static void assignConstants(AttrContainer container,
115: ClassType cl) {
116: for (Attribute attr = container.getAttributes(); attr != null; attr = attr.next) {
117: if (!attr.isSkipped())
118: attr.assignConstants(cl);
119: }
120: }
121:
122: /** Return the length of the attribute in bytes.
123: * Does not include the 6-byte header (for the name_index and the length).*/
124: abstract public int getLength();
125:
126: /** Return the length of all the attributes (with headers) in bytes. */
127: public static int getLengthAll(AttrContainer container) {
128: int length = 0;
129: for (Attribute attr = container.getAttributes(); attr != null; attr = attr.next) {
130: if (!attr.isSkipped())
131: length += 6 + attr.getLength();
132: }
133: return length;
134: }
135:
136: /** Write out the contents of the Attribute.
137: * Does not write the 6-byte attribute header. */
138: abstract public void write(DataOutputStream dstr)
139: throws java.io.IOException;
140:
141: public static int count(AttrContainer container) {
142: int count = 0;
143: for (Attribute attr = container.getAttributes(); attr != null; attr = attr.next) {
144: if (!attr.isSkipped())
145: count++;
146: }
147: return count;
148: }
149:
150: public static void writeAll(AttrContainer container,
151: DataOutputStream dstr) throws java.io.IOException {
152: int count = count(container);
153: dstr.writeShort(count);
154: for (Attribute attr = container.getAttributes(); attr != null; attr = attr.next) {
155: if (attr.isSkipped())
156: continue;
157: if (attr.name_index == 0)
158: throw new Error(
159: "Attribute.writeAll called without assignConstants");
160: dstr.writeShort(attr.name_index);
161: dstr.writeInt(attr.getLength());
162: attr.write(dstr);
163: }
164: }
165:
166: public void print(ClassTypeWriter dst) {
167: dst.print("Attribute \"");
168: dst.print(getName());
169: dst.print("\", length:");
170: dst.println(getLength());
171: }
172:
173: };
|