jasm.lang.BytecodeAttribute Maven / Gradle / Ivy
// Copyright (c) 2011, David J. Pearce ([email protected])
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL DAVID J. PEARCE BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package jasm.lang;
import jasm.io.BinaryInputStream;
import jasm.io.BinaryOutputStream;
import java.util.*;
import java.io.*;
public interface BytecodeAttribute {
public String name();
/**
* This method requires the attribute to write itself to the binary stream.
*
* @param writer
* Outputstream to which the attribute should be written.
* @param constantPool
* Map of CONSTANT_info items to their index in the constant pool.
*
* @throws IOException
*/
public void write(BinaryOutputStream writer,
Map constantPool) throws IOException;
/**
* When this method is called, the attribute must add all items that it
* needs to the constant pool.
*
* @param constantPool
*/
public void addPoolItems(Set constantPool);
/**
* This method is used to print the contents of the attribute in
* human-readable form, similar to that produced by "javap".
*
* @param output
* Output writer to which the attribute is printed.
* @param constantPool
* Map of CONSTANT_info items to their index in the constant
* pool.
* @throws IOException
*/
public void print(PrintWriter output,
Map constantPool) throws IOException;
/**
* Class for representing unknown attributes. This class does not write the
* same attribute back out but, instead, boxes inside a specia "Unknown"
* attribute. The reason for this is that, if the attribute contains e.g.
* constant pool items, then their indices may be incorrect.
*
* @author David J. Pearce
*/
public static class Unknown implements BytecodeAttribute {
private byte[] bytes;
private String name;
public Unknown(String n, byte[] bs) {
bytes = bs;
name = n;
}
public String name() {
return "Unknown";
}
public void addPoolItems(Set constantPool) {
Constant.addPoolItem(new Constant.Utf8("Unknown"), constantPool);
Constant.addPoolItem(new Constant.Utf8(name), constantPool);
}
public void write(BinaryOutputStream writer,
Map constantPool) throws IOException {
writer.write_u16(constantPool.get(new Constant.Utf8("Unknown")));
writer.write_u32(bytes.length);
writer.write(bytes);
}
public void print(PrintWriter output,
Map constantPool) throws IOException {
output.println(" Unknown: " + name);
output.println(" Size: " + bytes.length);
}
}
public static class Fn {
/**
* Read a list of BytecodeAttributes from an input stream, using the
* given constant pool and readers map to decode them.
*
* @param count
* --- number of attributes to read
* @param input
* --- input stream to read from
* @param constantPool
* --- pool for decoding constants
* @param readers
* --- list of decoders for reading attributes
* @return
*/
public static List read(int count,
BinaryInputStream input,
Map constantPool,
Map readers)
throws IOException {
ArrayList attributes = new ArrayList();
for (int i = 0; i != count; ++i) {
attributes.add(read(input, constantPool, readers));
}
return attributes;
}
/**
* Read a BytecodeAttribute from an input stream, using the given
* constant pool and readers map to decode them.
*
* @param input
* --- input stream to read from
* @param constantPool
* --- pool for decoding constants
* @param readers
* --- list of decoders for reading attributes
* @return
*/
public static BytecodeAttribute read(BinaryInputStream input,
Map constantPool,
Map readers)
throws IOException {
int index = input.read_u16();
int origLen = (int) input.read_u32();
int len = origLen + 6;
Constant.Utf8 cu = (Constant.Utf8) constantPool.get(index);
byte[] bs = new byte[len];
for (int i = 6; i != len; ++i) {
bs[i] = (byte) input.read();
}
// restore the header data we've already read
bs[0] = (byte) ((index >> 8) & 0xFF);
bs[1] = (byte) (index & 0xFF);
bs[2] = (byte) ((origLen >> 24) & 0xFF);
bs[3] = (byte) ((origLen >> 16) & 0xFF);
bs[4] = (byte) ((origLen >> 8) & 0xFF);
bs[5] = (byte) (origLen & 0xFF);
BytecodeAttribute.Reader reader = readers.get(cu.str);
if (reader != null) {
try {
return reader.read(new BinaryInputStream(
new ByteArrayInputStream(bs)), constantPool);
} catch (IOException ioex) {
throw new RuntimeException(ioex.getMessage(), ioex);
}
} else {
// unknown attribute
return new BytecodeAttribute.Unknown(cu.str, bs);
}
}
}
/**
* A BytecodeAttribute.Reader is an interface used for reading a given kind
* of BytecodeAttribute. The name returned by the reader is used to
* determine those bytecode attributes it will read (i.e. those with the
* same name).
*
* @author David J. Pearce
*
*/
public static interface Reader {
public String name();
public BytecodeAttribute read(BinaryInputStream input,
Map constantPool) throws IOException;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy