I threw this together if anyone wants to muck with it. It creates a classfile like this:
public class D {
public static final String D = "....";
}
where “…” is the passed in byte array. The assumption here is that an optimizer will be used to inline the String.
The “major” issue:
The UTF8 data chunk must be valid. So the byte array must be converted into/outof UTF8
for usage. Or some other encoding method. (SEE: 4.4.7 The CONSTANT_Utf8_info Structure) for details.
import java.io.*;
import java.lang.reflect.*;
/**
* Create a class as:
* <code>
* public class D {
* public static final String D = "....";
* }
* </code>
* where "...." contains the specified byte array.
*/
public class MakeData
{
private static final int[] prefix =
{
0xcafebabe, 0x00000032, 0x000e0a00, 0x03000b07,
0x00040700, 0x0c010001, 0x44010012, 0x4c6a6176,
0x612f6c61, 0x6e672f53, 0x7472696e, 0x673b0100,
0x0d436f6e, 0x7374616e, 0x7456616c, 0x75650800,
0x0d010006, 0x3c696e69, 0x743e0100, 0x03282956,
0x01000443, 0x6f64650c, 0x00080009, 0x0100106a,
0x6176612f, 0x6c616e67, 0x2f4f626a, 0x65637401
};
private static final int[] postfix =
{
0x00210002, 0x00030000, 0x00010019, 0x00040005,
0x00010006, 0x00000002, 0x00070001, 0x00010008,
0x00090001, 0x000a0000, 0x00110001, 0x00010000,
0x00052ab7, 0x0001b100
};
public static void createClassfile(byte[] data)
{
byte[] cf = create(data);
try {
FileOutputStream out = new FileOutputStream("D.class");
out.write(cf);
}
catch(FileNotFoundException e) {
System.err.println("error: failed to open.");
}
catch (IOException e) {
System.err.println("error: write failed.");
}
}
/**
* Creates the classfile bytes.
*/
public static byte[] create(byte[] data)
{
byte[] dst = new byte[data.length+168+2+5];
int j = 0;
for(int i = 0; i<prefix.length; i++) {
int c = prefix[i];
dst[j ] = (byte)(c >>> 24);
dst[j+1] = (byte)(c >>> 16);
dst[j+2] = (byte)(c >>> 8);
dst[j+3] = (byte)(c );
j += 4;
}
// The length of the UTF8 chunk
dst[j++] = (byte)(data.length >> 8);
dst[j++] = (byte)(data.length);
// Shove the data into the UTF8 chunk
for(int i = 0; i<data.length; i++) {
dst[j++] = data[i];
}
for(int i = 0; i<postfix.length; i++) {
int c = postfix[i];
dst[j ] = (byte)(c >>> 24);
dst[j+1] = (byte)(c >>> 16);
dst[j+2] = (byte)(c >>> 8);
dst[j+3] = (byte)(c );
j += 4;
}
return dst;
}
// ALL TESTING BELOW HERE
static class TestingLoader extends ClassLoader
{
byte[] data;
public TestingLoader(byte[] data)
{
this.data = data;
}
@Override
public Class<?> findClass(String name)
{
byte[] b = loadClassData(name);
return defineClass(name, b, 0, b.length);
}
private byte[] loadClassData(String name)
{
return data;
}
}
public static void test(byte[] cf, byte[] src)
{
try {
ClassLoader cl = new TestingLoader(cf);
Class<?> d = cl.loadClass("D");
String f = (String)d.getField("D").get(null);
byte[] out = new byte[f.length()];
f.getBytes(0,f.length(),out,0);
if (out.length == src.length) {
for(int i = 0; i < out.length; i++) {
if (src[i] == out[i])
continue;
System.err.println("broken");
}
return;
}
System.err.println("broken");
}
catch (Exception e)
{
System.err.println("problem");
e.printStackTrace();
}
}
public static void main(String[] args)
{
int n = 0x7e;
byte[] src = new byte[n];
for(int i = 0; i<n; i++)
src[i] = (byte)(i+1);
byte[] cf = create(src);
createClassfile(src);
test(cf,src);
System.exit(0);
}
}