--- /dev/null
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999-2010 Shigeru Chiba. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. Alternatively, the contents of this file may be used under
+ * the terms of the GNU Lesser General Public License Version 2.1 or later.
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ */
+
+package javassist.bytecode;
+
+import java.io.OutputStream;
+import java.io.IOException;
+
+final class ByteStream extends OutputStream {
+ private byte[] buf;
+ private int count;
+
+ public ByteStream() { this(32); }
+
+ public ByteStream(int size) {
+ buf = new byte[size];
+ count = 0;
+ }
+
+ public int getPos() { return count; }
+ public int size() { return count; }
+
+ public void writeBlank(int len) {
+ enlarge(len);
+ count += len;
+ }
+
+ public void write(byte[] data) {
+ write(data, 0, data.length);
+ }
+
+ public void write(byte[] data, int off, int len) {
+ enlarge(len);
+ System.arraycopy(data, off, buf, count, len);
+ count += len;
+ }
+
+ public void write(int b) {
+ enlarge(1);
+ int oldCount = count;
+ buf[oldCount] = (byte)b;
+ count = oldCount + 1;
+ }
+
+ public void writeShort(int s) {
+ enlarge(2);
+ int oldCount = count;
+ buf[oldCount] = (byte)(s >>> 8);
+ buf[oldCount + 1] = (byte)s;
+ count = oldCount + 2;
+ }
+
+ public void writeInt(int i) {
+ enlarge(4);
+ int oldCount = count;
+ buf[oldCount] = (byte)(i >>> 24);
+ buf[oldCount + 1] = (byte)(i >>> 16);
+ buf[oldCount + 2] = (byte)(i >>> 8);
+ buf[oldCount + 3] = (byte)i;
+ count = oldCount + 4;
+ }
+
+ public void writeLong(long i) {
+ enlarge(8);
+ int oldCount = count;
+ buf[oldCount] = (byte)(i >>> 56);
+ buf[oldCount + 1] = (byte)(i >>> 48);
+ buf[oldCount + 2] = (byte)(i >>> 40);
+ buf[oldCount + 3] = (byte)(i >>> 32);
+ buf[oldCount + 4] = (byte)(i >>> 24);
+ buf[oldCount + 5] = (byte)(i >>> 16);
+ buf[oldCount + 6] = (byte)(i >>> 8);
+ buf[oldCount + 7] = (byte)i;
+ count = oldCount + 8;
+ }
+
+ public void writeFloat(float v) {
+ writeInt(Float.floatToIntBits(v));
+ }
+
+ public void writeDouble(double v) {
+ writeLong(Double.doubleToLongBits(v));
+ }
+
+ public void writeUTF(String s) {
+ int sLen = s.length();
+ int pos = count;
+ enlarge(sLen + 2);
+
+ byte[] buffer = buf;
+ buffer[pos++] = (byte)(sLen >>> 8);
+ buffer[pos++] = (byte)sLen;
+ for (int i = 0; i < sLen; ++i) {
+ char c = s.charAt(i);
+ if (0x01 <= c && c <= 0x7f)
+ buffer[pos++] = (byte)c;
+ else {
+ writeUTF2(s, sLen, i);
+ return;
+ }
+ }
+
+ count = pos;
+ }
+
+ private void writeUTF2(String s, int sLen, int offset) {
+ int size = sLen;
+ for (int i = offset; i < sLen; i++) {
+ int c = s.charAt(i);
+ if (c > 0x7ff)
+ size += 2; // 3 bytes code
+ else if (c == 0 || c > 0x7f)
+ ++size; // 2 bytes code
+ }
+
+ if (size > 65535)
+ throw new RuntimeException(
+ "encoded string too long: " + sLen + size + " bytes");
+
+ enlarge(size + 2);
+ int pos = count;
+ byte[] buffer = buf;
+ buffer[pos] = (byte)(size >>> 8);
+ buffer[pos + 1] = (byte)size;
+ pos += 2 + offset;
+ for (int j = offset; j < sLen; ++j) {
+ int c = s.charAt(j);
+ if (0x01 <= c && c <= 0x7f)
+ buffer[pos++] = (byte) c;
+ else if (c > 0x07ff) {
+ buffer[pos] = (byte)(0xe0 | ((c >> 12) & 0x0f));
+ buffer[pos + 1] = (byte)(0x80 | ((c >> 6) & 0x3f));
+ buffer[pos + 2] = (byte)(0x80 | (c & 0x3f));
+ pos += 3;
+ }
+ else {
+ buffer[pos] = (byte)(0xc0 | ((c >> 6) & 0x1f));
+ buffer[pos + 1] = (byte)(0x80 | (c & 0x3f));
+ pos += 2;
+ }
+ }
+
+ count = pos;
+ }
+
+ public void write(int pos, int value) {
+ buf[pos] = (byte)value;
+ }
+
+ public void writeShort(int pos, int value) {
+ buf[pos] = (byte)(value >>> 8);
+ buf[pos + 1] = (byte)value;
+ }
+
+ public void writeInt(int pos, int value) {
+ buf[pos] = (byte)(value >>> 24);
+ buf[pos + 1] = (byte)(value >>> 16);
+ buf[pos + 2] = (byte)(value >>> 8);
+ buf[pos + 3] = (byte)value;
+ }
+
+ public byte[] toByteArray() {
+ byte[] buf2 = new byte[count];
+ System.arraycopy(buf, 0, buf2, 0, count);
+ return buf2;
+ }
+
+ public void writeTo(OutputStream out) throws IOException {
+ out.write(buf, 0, count);
+ }
+
+ public void enlarge(int delta) {
+ int newCount = count + delta;
+ if (newCount > buf.length) {
+ int newLen = buf.length << 1;
+ byte[] newBuf = new byte[newLen > newCount ? newLen : newCount];
+ System.arraycopy(buf, 0, newBuf, 0, count);
+ buf = newBuf;
+ }
+ }
+}
--- /dev/null
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999-2010 Shigeru Chiba. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. Alternatively, the contents of this file may be used under
+ * the terms of the GNU Lesser General Public License Version 2.1 or later.
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ */
+
+package javassist.bytecode;
+
+import java.io.OutputStream;
+import java.io.DataOutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+/**
+ * A quick class-file writer. This is useful when a generated
+ * class file is simple and the code generation should be fast.
+ *
+ * <p>Example:
+ *
+ * <blockquote><pre>
+ * ClassFileWriter cfw = new ClassFileWriter(ClassFile.JAVA_4, 0);
+ * ConstPoolWriter cpw = cfw.getConstPool();
+ *
+ * FieldWriter fw = cfw.getFieldWriter();
+ * fw.add(AccessFlag.PUBLIC, "value", "I", null);
+ * fw.add(AccessFlag.PUBLIC, "value2", "J", null);
+ *
+ * int thisClass = cpw.addClassInfo("sample/Test");
+ * int superClass = cpw.addClassInfo("java/lang/Object");
+ *
+ * MethodWriter mw = cfw.getMethodWriter();
+ *
+ * mw.begin(AccessFlag.PUBLIC, MethodInfo.nameInit, "()V", null, null);
+ * mw.add(Opcode.ALOAD_0);
+ * mw.add(Opcode.INVOKESPECIAL);
+ * int signature = cpw.addNameAndTypeInfo(MethodInfo.nameInit, "()V");
+ * mw.add16(cpw.addMethodrefInfo(superClass, signature));
+ * mw.add(Opcode.RETURN);
+ * mw.codeEnd(1, 1);
+ * mw.end(null, null);
+ *
+ * mw.begin(AccessFlag.PUBLIC, "one", "()I", null, null);
+ * mw.add(Opcode.ICONST_1);
+ * mw.add(Opcode.IRETURN);
+ * mw.codeEnd(1, 1);
+ * mw.end(null, null);
+ *
+ * byte[] classfile = cfw.end(AccessFlag.PUBLIC, thisClass, superClass,
+ * null, null);
+ * </pre></blockquote>
+ *
+ * <p>The code above generates the following class:
+ *
+ * <blockquote><pre>
+ * package sample;
+ * public class Test {
+ * public int value;
+ * public long value2;
+ * public Test() { super(); }
+ * public one() { return 1; }
+ * }
+ * </pre></blockquote>
+ *
+ * @since 3.13
+ */
+public class ClassFileWriter {
+ private ByteStream output;
+ private ConstPoolWriter constPool;
+ private FieldWriter fields;
+ private MethodWriter methods;
+ int thisClass, superClass;
+
+ /**
+ * Constructs a class file writer.
+ *
+ * @param major the major version ({@link ClassFile#JAVA_4}, {@link ClassFile#JAVA_5}, ...).
+ * @param minor the minor version (0 for JDK 1.3 and later).
+ */
+ public ClassFileWriter(int major, int minor) {
+ output = new ByteStream(512);
+ output.writeInt(0xCAFEBABE); // magic
+ output.writeShort(minor);
+ output.writeShort(major);
+ constPool = new ConstPoolWriter(output);
+ fields = new FieldWriter(constPool);
+ methods = new MethodWriter(constPool);
+
+ }
+
+ /**
+ * Returns a constant pool.
+ */
+ public ConstPoolWriter getConstPool() { return constPool; }
+
+ /**
+ * Returns a filed writer.
+ */
+ public FieldWriter getFieldWriter() { return fields; }
+
+ /**
+ * Returns a method writer.
+ */
+ public MethodWriter getMethodWriter() { return methods; }
+
+ /**
+ * Ends writing and returns the contents of the class file.
+ *
+ * @param accessFlags access flags.
+ * @param thisClass this class. an index indicating its <code>CONSTANT_Class_info</code>.
+ * @param superClass super class. an index indicating its <code>CONSTANT_Class_info</code>.
+ * @param interfaces implemented interfaces.
+ * index numbers indicating their <code>ClassInfo</code>.
+ * It may be null.
+ * @param aw attributes of the class file. May be null.
+ *
+ * @see AccessFlag
+ */
+ public byte[] end(int accessFlags, int thisClass, int superClass,
+ int[] interfaces, AttributeWriter aw) {
+ constPool.end();
+ output.writeShort(accessFlags);
+ output.writeShort(thisClass);
+ output.writeShort(superClass);
+ if (interfaces == null)
+ output.writeShort(0);
+ else {
+ int n = interfaces.length;
+ output.writeShort(n);
+ for (int i = 0; i < n; i++)
+ output.writeShort(interfaces[i]);
+ }
+
+ output.enlarge(fields.dataSize() + methods.dataSize() + 6);
+ try {
+ output.writeShort(fields.size());
+ fields.write(output);
+
+ output.writeShort(methods.size());
+ methods.write(output);
+ }
+ catch (IOException e) {}
+
+ writeAttribute(output, aw, 0);
+ return output.toByteArray();
+ }
+
+ /**
+ * Ends writing and writes the contents of the class file into the
+ * given output stream.
+ *
+ * @param accessFlags access flags.
+ * @param thisClass this class. an index indicating its <code>CONSTANT_Class_info</code>.
+ * @param superClass super class. an index indicating its <code>CONSTANT_Class_info</code>.
+ * @param interfaces implemented interfaces.
+ * index numbers indicating their <code>CONSTATNT_Class_info</code>.
+ * It may be null.
+ * @param aw attributes of the class file. May be null.
+ *
+ * @see AccessFlag
+ */
+ public void end(DataOutputStream out,
+ int accessFlags, int thisClass, int superClass,
+ int[] interfaces, AttributeWriter aw)
+ throws IOException
+ {
+ constPool.end();
+ output.writeTo(out);
+ out.writeShort(accessFlags);
+ out.writeShort(thisClass);
+ out.writeShort(superClass);
+ if (interfaces == null)
+ out.writeShort(0);
+ else {
+ int n = interfaces.length;
+ out.writeShort(n);
+ for (int i = 0; i < n; i++)
+ out.writeShort(interfaces[i]);
+ }
+
+ out.writeShort(fields.size());
+ fields.write(out);
+
+ out.writeShort(methods.size());
+ methods.write(out);
+ if (aw == null)
+ out.writeShort(0);
+ else {
+ out.writeShort(aw.size());
+ aw.write(out);
+ }
+ }
+
+ /**
+ * This writes attributes.
+ *
+ * <p>For example, the following object writes a synthetic attribute:
+ *
+ * <pre>
+ * ConstPoolWriter cpw = ...;
+ * final int tag = cpw.addUtf8Info("Synthetic");
+ * AttributeWriter aw = new AttributeWriter() {
+ * public int size() {
+ * return 1;
+ * }
+ * public void write(DataOutputStream out) throws java.io.IOException {
+ * out.writeShort(tag);
+ * out.writeInt(0);
+ * }
+ * };
+ * </pre>
+ */
+ public static interface AttributeWriter {
+ /**
+ * Returns the number of attributes that this writer will
+ * write.
+ */
+ public int size();
+
+ /**
+ * Writes all the contents of the attributes. The binary representation
+ * of the contents is an array of <code>attribute_info</code>.
+ */
+ public void write(DataOutputStream out) throws IOException;
+ }
+
+ static void writeAttribute(ByteStream bs, AttributeWriter aw, int attrCount) {
+ if (aw == null) {
+ bs.writeShort(attrCount);
+ return;
+ }
+
+ bs.writeShort(aw.size() + attrCount);
+ DataOutputStream dos = new DataOutputStream(bs);
+ try {
+ aw.write(dos);
+ dos.flush();
+ }
+ catch (IOException e) {}
+ }
+
+ /**
+ * Field.
+ */
+ public static final class FieldWriter {
+ protected ByteStream output;
+ protected ConstPoolWriter constPool;
+ private int fieldCount;
+
+ FieldWriter(ConstPoolWriter cp) {
+ output = new ByteStream(128);
+ constPool = cp;
+ fieldCount = 0;
+ }
+
+ /**
+ * Adds a new field.
+ *
+ * @param accessFlags access flags.
+ * @param name the field name.
+ * @param descriptor the field type.
+ * @param aw the attributes of the field. may be null.
+ * @see AccessFlag
+ */
+ public void add(int accessFlags, String name, String descriptor, AttributeWriter aw) {
+ int nameIndex = constPool.addUtf8Info(name);
+ int descIndex = constPool.addUtf8Info(descriptor);
+ add(accessFlags, nameIndex, descIndex, aw);
+ }
+
+ /**
+ * Adds a new field.
+ *
+ * @param accessFlags access flags.
+ * @param name the field name. an index indicating its <code>CONSTANT_Utf8_info</code>.
+ * @param descriptor the field type. an index indicating its <code>CONSTANT_Utf8_info</code>.
+ * @param aw the attributes of the field. may be null.
+ * @see AccessFlag
+ */
+ public void add(int accessFlags, int name, int descriptor, AttributeWriter aw) {
+ ++fieldCount;
+ output.writeShort(accessFlags);
+ output.writeShort(name);
+ output.writeShort(descriptor);
+ writeAttribute(output, aw, 0);
+ }
+
+ int size() { return fieldCount; }
+
+ int dataSize() { return output.size(); }
+
+ /**
+ * Writes the added fields.
+ */
+ void write(OutputStream out) throws IOException {
+ output.writeTo(out);
+ }
+ }
+
+ /**
+ * Method.
+ */
+ public static final class MethodWriter {
+ protected ByteStream output;
+ protected ConstPoolWriter constPool;
+ private int methodCount;
+ protected int codeIndex;
+ protected int throwsIndex;
+ protected int stackIndex;
+
+ private int startPos;
+ private boolean isAbstract;
+ private int catchPos;
+ private int catchCount;
+
+ MethodWriter(ConstPoolWriter cp) {
+ output = new ByteStream(256);
+ constPool = cp;
+ methodCount = 0;
+ codeIndex = 0;
+ throwsIndex = 0;
+ stackIndex = 0;
+ }
+
+ /**
+ * Starts Adding a new method.
+ *
+ * @param accessFlags access flags.
+ * @param name the method name.
+ * @param descriptor the method signature.
+ * @param exceptions throws clause. It may be null.
+ * The class names must be the JVM-internal
+ * representations like <code>java/lang/Exception</code>.
+ * @param aw attributes to the <code>Method_info</code>.
+ */
+ public void begin(int accessFlags, String name, String descriptor,
+ String[] exceptions, AttributeWriter aw) {
+ int nameIndex = constPool.addUtf8Info(name);
+ int descIndex = constPool.addUtf8Info(descriptor);
+ int[] intfs;
+ if (exceptions == null)
+ intfs = null;
+ else
+ intfs = constPool.addClassInfo(exceptions);
+
+ begin(accessFlags, nameIndex, descIndex, intfs, aw);
+ }
+
+ /**
+ * Starts adding a new method.
+ *
+ * @param accessFlags access flags.
+ * @param name the method name. an index indicating its <code>CONSTANT_Utf8_info</code>.
+ * @param descriptor the field type. an index indicating its <code>CONSTANT_Utf8_info</code>.
+ * @param exceptions throws clause. indexes indicating <code>CONSTANT_Class_info</code>s.
+ * It may be null.
+ * @param aw attributes to the <code>Method_info</code>.
+ */
+ public void begin(int accessFlags, int name, int descriptor, int[] exceptions, AttributeWriter aw) {
+ ++methodCount;
+ output.writeShort(accessFlags);
+ output.writeShort(name);
+ output.writeShort(descriptor);
+ isAbstract = (accessFlags & AccessFlag.ABSTRACT) != 0;
+
+ int attrCount = isAbstract ? 0 : 1;
+ if (exceptions != null)
+ ++attrCount;
+
+ writeAttribute(output, aw, attrCount);
+
+ if (exceptions != null)
+ writeThrows(exceptions);
+
+ if (!isAbstract) {
+ if (codeIndex == 0)
+ codeIndex = constPool.addUtf8Info(CodeAttribute.tag);
+
+ startPos = output.getPos();
+ output.writeShort(codeIndex);
+ output.writeBlank(12); // attribute_length, maxStack, maxLocals, code_lenth
+ }
+
+ catchPos = -1;
+ catchCount = 0;
+ }
+
+ private void writeThrows(int[] exceptions) {
+ if (throwsIndex == 0)
+ throwsIndex = constPool.addUtf8Info(ExceptionsAttribute.tag);
+
+ output.writeShort(throwsIndex);
+ output.writeInt(exceptions.length * 2 + 2);
+ output.writeShort(exceptions.length);
+ for (int i = 0; i < exceptions.length; i++)
+ output.writeShort(exceptions[i]);
+ }
+
+ /**
+ * Appends an 8bit value of bytecode.
+ *
+ * @see Opcode
+ */
+ public void add(int b) {
+ output.write(b);
+ }
+
+ /**
+ * Appends a 16bit value of bytecode.
+ */
+ public void add16(int b) {
+ output.writeShort(b);
+ }
+
+ /**
+ * Appends a 32bit value of bytecode.
+ */
+ public void add32(int b) {
+ output.writeInt(b);
+ }
+
+ /**
+ * Appends a invokevirtual, inovkespecial, or invokestatic bytecode.
+ *
+ * @see Opcode
+ */
+ public void addInvoke(int opcode, String targetClass, String methodName,
+ String descriptor) {
+ int target = constPool.addClassInfo(targetClass);
+ int nt = constPool.addNameAndTypeInfo(methodName, descriptor);
+ int method = constPool.addMethodrefInfo(target, nt);
+ add(opcode);
+ add16(method);
+ }
+
+ /**
+ * Ends appending bytecode.
+ */
+ public void codeEnd(int maxStack, int maxLocals) {
+ if (!isAbstract) {
+ output.writeShort(startPos + 6, maxStack);
+ output.writeShort(startPos + 8, maxLocals);
+ output.writeInt(startPos + 10, output.getPos() - startPos - 14); // code_length
+ catchPos = output.getPos();
+ catchCount = 0;
+ output.writeShort(0); // number of catch clauses
+ }
+ }
+
+ /**
+ * Appends an <code>exception_table</code> entry to the
+ * <code>Code_attribute</code>. This method is available
+ * only after the <code>codeEnd</code> method is called.
+ *
+ * @param catchType an index indicating a <code>CONSTANT_Class_info</code>.
+ */
+ public void addCatch(int startPc, int endPc, int handlerPc, int catchType) {
+ ++catchCount;
+ output.writeShort(startPc);
+ output.writeShort(endPc);
+ output.writeShort(handlerPc);
+ output.writeShort(catchType);
+ }
+
+ /**
+ * Ends adding a new method. The <code>add</code> method must be
+ * called before the <code>end</code> method is called.
+ *
+ * @param smap a stack map table. may be null.
+ * @param aw attributes to the <code>Code_attribute</code>.
+ * may be null.
+ */
+ public void end(StackMapTable.Writer smap, AttributeWriter aw) {
+ if (isAbstract)
+ return;
+
+ // exception_table_length
+ output.writeShort(catchPos, catchCount);
+
+ int attrCount = smap == null ? 0 : 1;
+ writeAttribute(output, aw, attrCount);
+
+ if (smap != null) {
+ if (stackIndex == 0)
+ stackIndex = constPool.addUtf8Info(StackMapTable.tag);
+
+ output.writeShort(stackIndex);
+ byte[] data = smap.toByteArray();
+ output.writeInt(data.length);
+ output.write(data);
+ }
+
+ // Code attribute_length
+ output.writeInt(startPos + 2, output.getPos() - startPos - 6);
+ }
+
+ int size() { return methodCount; }
+
+ int dataSize() { return output.size(); }
+
+ /**
+ * Writes the added methods.
+ */
+ void write(OutputStream out) throws IOException {
+ output.writeTo(out);
+ }
+ }
+
+ /**
+ * Constant Pool.
+ */
+ public static final class ConstPoolWriter {
+ ByteStream output;
+ protected int startPos;
+ protected int num;
+
+ ConstPoolWriter(ByteStream out) {
+ output = out;
+ startPos = out.getPos();
+ num = 1;
+ output.writeShort(1); // number of entries
+ }
+
+ /**
+ * Makes <code>CONSTANT_Class_info</code> objects for each class name.
+ *
+ * @return an array of indexes indicating <code>CONSTANT_Class_info</code>s.
+ */
+ public int[] addClassInfo(String[] classNames) {
+ int n = classNames.length;
+ int[] result = new int[n];
+ for (int i = 0; i < n; i++)
+ result[i] = addClassInfo(classNames[i]);
+
+ return result;
+ }
+
+ /**
+ * Adds a new <code>CONSTANT_Class_info</code> structure.
+ *
+ * <p>This also adds a <code>CONSTANT_Utf8_info</code> structure
+ * for storing the class name.
+ *
+ * @param jvmname the JVM-internal representation of a class name.
+ * e.g. <code>java/lang/Object</code>.
+ * @return the index of the added entry.
+ */
+ public int addClassInfo(String jvmname) {
+ int utf8 = addUtf8Info(jvmname);
+ output.write(ClassInfo.tag);
+ output.writeShort(utf8);
+ return num++;
+ }
+
+ /**
+ * Adds a new <code>CONSTANT_Class_info</code> structure.
+ *
+ * @param name <code>name_index</code>
+ * @return the index of the added entry.
+ */
+ public int addClassInfo(int name) {
+ output.write(ClassInfo.tag);
+ output.writeShort(name);
+ return num++;
+ }
+
+ /**
+ * Adds a new <code>CONSTANT_NameAndType_info</code> structure.
+ *
+ * @param name <code>name_index</code>
+ * @param type <code>descriptor_index</code>
+ * @return the index of the added entry.
+ */
+ public int addNameAndTypeInfo(String name, String type) {
+ return addNameAndTypeInfo(addUtf8Info(name), addUtf8Info(type));
+ }
+
+ /**
+ * Adds a new <code>CONSTANT_NameAndType_info</code> structure.
+ *
+ * @param name <code>name_index</code>
+ * @param type <code>descriptor_index</code>
+ * @return the index of the added entry.
+ */
+ public int addNameAndTypeInfo(int name, int type) {
+ output.write(NameAndTypeInfo.tag);
+ output.writeShort(name);
+ output.writeShort(type);
+ return num++;
+ }
+
+ /**
+ * Adds a new <code>CONSTANT_Fieldref_info</code> structure.
+ *
+ * @param classInfo <code>class_index</code>
+ * @param nameAndTypeInfo <code>name_and_type_index</code>.
+ * @return the index of the added entry.
+ */
+ public int addFieldrefInfo(int classInfo, int nameAndTypeInfo) {
+ output.write(FieldrefInfo.tag);
+ output.writeShort(classInfo);
+ output.writeShort(nameAndTypeInfo);
+ return num++;
+ }
+
+ /**
+ * Adds a new <code>CONSTANT_Methodref_info</code> structure.
+ *
+ * @param classInfo <code>class_index</code>
+ * @param nameAndTypeInfo <code>name_and_type_index</code>.
+ * @return the index of the added entry.
+ */
+ public int addMethodrefInfo(int classInfo, int nameAndTypeInfo) {
+ output.write(MethodrefInfo.tag);
+ output.writeShort(classInfo);
+ output.writeShort(nameAndTypeInfo);
+ return num++;
+ }
+
+ /**
+ * Adds a new <code>CONSTANT_InterfaceMethodref_info</code>
+ * structure.
+ *
+ * @param classInfo <code>class_index</code>
+ * @param nameAndTypeInfo <code>name_and_type_index</code>.
+ * @return the index of the added entry.
+ */
+ public int addInterfaceMethodrefInfo(int classInfo,
+ int nameAndTypeInfo) {
+ output.write(InterfaceMethodrefInfo.tag);
+ output.writeShort(classInfo);
+ output.writeShort(nameAndTypeInfo);
+ return num++;
+ }
+
+ /**
+ * Adds a new <code>CONSTANT_String_info</code>
+ * structure.
+ *
+ * <p>This also adds a new <code>CONSTANT_Utf8_info</code>
+ * structure.
+ *
+ * @return the index of the added entry.
+ */
+ public int addStringInfo(String str) {
+ output.write(StringInfo.tag);
+ output.writeShort(addUtf8Info(str));
+ return num++;
+ }
+
+ /**
+ * Adds a new <code>CONSTANT_Integer_info</code>
+ * structure.
+ *
+ * @return the index of the added entry.
+ */
+ public int addIntegerInfo(int i) {
+ output.write(IntegerInfo.tag);
+ output.writeInt(i);
+ return num++;
+ }
+
+ /**
+ * Adds a new <code>CONSTANT_Float_info</code>
+ * structure.
+ *
+ * @return the index of the added entry.
+ */
+ public int addFloatInfo(float f) {
+ output.write(FloatInfo.tag);
+ output.writeFloat(f);
+ return num++;
+ }
+
+ /**
+ * Adds a new <code>CONSTANT_Long_info</code>
+ * structure.
+ *
+ * @return the index of the added entry.
+ */
+ public int addLongInfo(long l) {
+ output.write(LongInfo.tag);
+ output.writeLong(l);
+ int n = num;
+ num += 2;
+ return n;
+ }
+
+ /**
+ * Adds a new <code>CONSTANT_Double_info</code>
+ * structure.
+ *
+ * @return the index of the added entry.
+ */
+ public int addDoubleInfo(double d) {
+ output.write(DoubleInfo.tag);
+ output.writeDouble(d);
+ int n = num;
+ num += 2;
+ return n;
+ }
+
+ /**
+ * Adds a new <code>CONSTANT_Utf8_info</code>
+ * structure.
+ *
+ * @return the index of the added entry.
+ */
+ public int addUtf8Info(String utf8) {
+ output.write(Utf8Info.tag);
+ output.writeUTF(utf8);
+ return num++;
+ }
+
+ /**
+ * Writes the contents of this class pool.
+ */
+ void end() {
+ output.writeShort(startPos, num);
+ }
+ }
+}