001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.harmony.pack200.bytecode;
018:
019: import java.io.DataOutputStream;
020: import java.io.IOException;
021: import java.util.ArrayList;
022: import java.util.Iterator;
023: import java.util.List;
024:
025: /**
026: * A New (i.e. non-predefined) Class File attribute
027: */
028: public class NewAttribute extends BCIRenumberedAttribute {
029:
030: private List lengths = new ArrayList(); // List of Integers
031: private List body = new ArrayList();
032: private ClassConstantPool pool;
033:
034: public NewAttribute(String attributeName) {
035: super (attributeName);
036: }
037:
038: /* (non-Javadoc)
039: * @see org.apache.harmony.pack200.bytecode.Attribute#getLength()
040: */
041: protected int getLength() {
042: int length = 0;
043: for (Iterator iter = lengths.iterator(); iter.hasNext();) {
044: length += ((Integer) iter.next()).intValue();
045: }
046: return length;
047: }
048:
049: /* (non-Javadoc)
050: * @see org.apache.harmony.pack200.bytecode.Attribute#writeBody(java.io.DataOutputStream)
051: */
052: protected void writeBody(DataOutputStream dos) throws IOException {
053: for (int i = 0; i < lengths.size(); i++) {
054: int length = ((Integer) lengths.get(i)).intValue();
055: Object obj = body.get(i);
056: long value = 0;
057: if (obj instanceof Long) {
058: value = ((Long) obj).longValue();
059: } else if (obj instanceof ClassFileEntry) {
060: value = pool.indexOf(((ClassFileEntry) obj));
061: } else if (obj instanceof BCValue) {
062: value = ((BCValue) obj).actualValue;
063: }
064: // Write
065: if (length == 1) {
066: dos.writeByte((int) value);
067: } else if (length == 2) {
068: dos.writeShort((int) value);
069: } else if (length == 4) {
070: dos.writeInt((int) value);
071: } else if (length == 8) {
072: dos.writeLong(value);
073: }
074: }
075: }
076:
077: /* (non-Javadoc)
078: * @see org.apache.harmony.pack200.bytecode.ClassFileEntry#toString()
079: */
080: public String toString() {
081: return attributeName.underlyingString();
082: }
083:
084: public void addInteger(int length, long value) {
085: lengths.add(new Integer(length));
086: body.add(new Long(value));
087: }
088:
089: public void addBCOffset(int length, int value) {
090: lengths.add(new Integer(length));
091: body.add(new BCOffset(value));
092: }
093:
094: public void addBCIndex(int length, int value) {
095: lengths.add(new Integer(length));
096: body.add(new BCIndex(value));
097: }
098:
099: public void addBCLength(int length, int value) {
100: lengths.add(new Integer(length));
101: body.add(new BCLength(value));
102: }
103:
104: public void addCPConstant(int length, CPConstant constant) {
105: lengths.add(new Integer(length));
106: body.add(constant);
107: }
108:
109: public void addCPClass(int length, CPClass class1) {
110: lengths.add(new Integer(length));
111: body.add(class1);
112: }
113:
114: public void addCPUTF8(int length, CPUTF8 cputf8) {
115: lengths.add(new Integer(length));
116: body.add(cputf8);
117: }
118:
119: public void addCPNameAndType(int length, CPNameAndType type) {
120: lengths.add(new Integer(length));
121: body.add(type);
122: }
123:
124: public void addCPFieldRef(int length, CPFieldRef ref) {
125: lengths.add(new Integer(length));
126: body.add(ref);
127: }
128:
129: public void addCPMethodRef(int length, CPMethodRef ref) {
130: lengths.add(new Integer(length));
131: body.add(ref);
132: }
133:
134: public void addCPIMethodRef(int length, CPInterfaceMethodRef ref) {
135: lengths.add(new Integer(length));
136: body.add(ref);
137: }
138:
139: protected void resolve(ClassConstantPool pool) {
140: super .resolve(pool);
141: for (Iterator iter = body.iterator(); iter.hasNext();) {
142: Object element = iter.next();
143: if (element instanceof ClassFileEntry) {
144: ((ClassFileEntry) element).resolve(pool);
145: }
146: }
147: this .pool = pool;
148: }
149:
150: private static class BCOffset extends BCValue {
151:
152: private int offset;
153: private int index;
154:
155: public BCOffset(int offset) {
156: this .offset = offset;
157: }
158:
159: public void setIndex(int index) {
160: this .index = index;
161: }
162:
163: }
164:
165: private static class BCIndex extends BCValue {
166:
167: private int index;
168:
169: public BCIndex(int index) {
170: this .index = index;
171: }
172: }
173:
174: private static class BCLength extends BCValue {
175:
176: private int length;
177:
178: public BCLength(int length) {
179: this .length = length;
180: }
181: }
182:
183: // Bytecode-related value (either a bytecode index or a length)
184: private static abstract class BCValue {
185:
186: int actualValue;
187:
188: public void setActualValue(int value) {
189: this .actualValue = value;
190: }
191:
192: }
193:
194: protected int[] getStartPCs() {
195: // Don't need to return anything here as we've overridden renumber
196: return null;
197: }
198:
199: public void renumber(List byteCodeOffsets) {
200: if (!renumbered) {
201: Object previous = null;
202: for (Iterator iter = body.iterator(); iter.hasNext();) {
203: Object obj = iter.next();
204: if (obj instanceof BCIndex) {
205: BCIndex bcIndex = (BCIndex) obj;
206: bcIndex.setActualValue(((Integer) byteCodeOffsets
207: .get(bcIndex.index)).intValue());
208: } else if (obj instanceof BCOffset) {
209: BCOffset bcOffset = (BCOffset) obj;
210: if (previous instanceof BCIndex) {
211: int index = ((BCIndex) previous).index
212: + bcOffset.offset;
213: bcOffset.setIndex(index);
214: bcOffset
215: .setActualValue(((Integer) byteCodeOffsets
216: .get(index)).intValue());
217: } else if (previous instanceof BCOffset) {
218: int index = ((BCOffset) previous).index
219: + bcOffset.offset;
220: bcOffset.setIndex(index);
221: bcOffset
222: .setActualValue(((Integer) byteCodeOffsets
223: .get(index)).intValue());
224: } else {
225: // Not sure if this should be able to happen
226: bcOffset
227: .setActualValue(((Integer) byteCodeOffsets
228: .get(bcOffset.offset))
229: .intValue());
230: }
231: } else if (obj instanceof BCLength) {
232: // previous must be a BCIndex
233: BCLength bcLength = (BCLength) obj;
234: BCIndex prevIndex = (BCIndex) previous;
235: int index = prevIndex.index + bcLength.length;
236: int actualLength = ((Integer) byteCodeOffsets
237: .get(index)).intValue()
238: - prevIndex.actualValue;
239: bcLength.setActualValue(actualLength);
240: }
241: previous = obj;
242: }
243: renumbered = true;
244: }
245: }
246:
247: }
|