// Copyright (c) 2011, David J. Pearce (djp@ecs.vuw.ac.nz)
// 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 <organization> 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.io;
import jasm.io.BinaryOutputStream;
import jasm.lang.*;
import jasm.util.Pair;
import jasm.verifier.ClassFileVerifier;
import java.io.*;
import java.util.*;
public class ClassFileWriter {
protected final BinaryOutputStream output;
/**
* Construct a ClassFileWriter Object that the given output stream to write
* ClassFiles.
*
* @param o
* Output stream for class bytes
*/
public ClassFileWriter(OutputStream o) {
output = new BinaryOutputStream(o);
}
public void write(ClassFile cfile) throws IOException {
ArrayList<Constant.Info> constantPool = cfile.constantPool();
HashMap<Constant.Info,Integer> poolMap = new HashMap<Constant.Info,Integer>();
int index = 0;
for(Constant.Info ci : constantPool) {
poolMap.put(ci, index++);
}
output.write_u8(0xCA);
output.write_u8(0xFE);
output.write_u8(0xBA);
output.write_u8(0xBE);
output.write_u32(cfile.version());
output.write_u16(constantPool.size());
// now, write the constant pool
for (Constant.Info c : constantPool) {
if (c != null) { // item at index 0 is always null
output.write(c.toBytes(poolMap));
}
}
// ok, done that now write more stuff
writeClassModifiers(cfile.modifiers());
output.write_u16(poolMap.get(Constant.buildClass(cfile.type())));
if (cfile.superClass() != null) {
output.write_u16(poolMap.get(Constant.buildClass(cfile.superClass())));
}
output.write_u16(cfile.interfaces().size());
for (JvmType.Reference i : cfile.interfaces()) {
output.write_u16(poolMap.get(Constant.buildClass(i)));
}
output.write_u16(cfile.fields().size());
for (ClassFile.Field f : cfile.fields()) {
writeField(f, poolMap);
}
output.write_u16(cfile.methods().size());
for (ClassFile.Method m : cfile.methods()) {
writeMethod(m, poolMap);
}
output.write_u16(cfile.attributes().size());
for(BytecodeAttribute a : cfile.attributes()) {
a.write(output, poolMap);
}
output.flush();
}
protected void writeField(ClassFile.Field f,
HashMap<Constant.Info, Integer> constantPool) throws IOException {
writeFieldModifiers(f.modifiers());
output.write_u16(constantPool.get(new Constant.Utf8(f.name())));
output.write_u16(constantPool.get(new Constant.Utf8(ClassFile
.descriptor(f.type(), false))));
// Write number of attributes
output.write_u16(f.attributes().size());
for (BytecodeAttribute a : f.attributes()) {
a.write(output, constantPool);
}
}
protected void writeMethod(ClassFile.Method m,
HashMap<Constant.Info, Integer> constantPool) throws IOException {
writeMethodModifiers(m.modifiers());
output.write_u16(constantPool.get(new Constant.Utf8(m.name())));
output.write_u16(constantPool.get(new Constant.Utf8(ClassFile
.descriptor(m.type(), false))));
output.write_u16(m.attributes().size());
for (BytecodeAttribute a : m.attributes()) {
a.write(output, constantPool);
}
}
protected void writeClassModifiers(List<Modifier> modifiers)
throws IOException {
int mods = 0;
for(Modifier m : modifiers) {
if(m instanceof Modifier.Public) {
mods |= ClassFileReader.ACC_PUBLIC;
} else if(m instanceof Modifier.Final) {
mods |= ClassFileReader.ACC_FINAL;
} else if(m instanceof Modifier.Super) {
mods |= ClassFileReader.ACC_SUPER;
} else if(m instanceof Modifier.Interface) {
mods |= ClassFileReader.ACC_INTERFACE;
} else if(m instanceof Modifier.Abstract) {
mods |= ClassFileReader.ACC_ABSTRACT;
} else if(m instanceof Modifier.Enum) {
mods |= ClassFileReader.ACC_ENUM;
}
}
output.write_u16(mods);
}
protected void writeFieldModifiers(List<Modifier> modifiers)
throws IOException {
int mods = 0;
for(Modifier m : modifiers) {
if(m instanceof Modifier.Public) {
mods |= ClassFileReader.ACC_PUBLIC;
} else if(m instanceof Modifier.Private) {
mods |= ClassFileReader.ACC_PRIVATE;
} else if(m instanceof Modifier.Protected) {
mods |= ClassFileReader.ACC_PROTECTED;
} else if(m instanceof Modifier.Static) {
mods |= ClassFileReader.ACC_STATIC;
} else if(m instanceof Modifier.Final) {
mods |= ClassFileReader.ACC_FINAL;
} else if(m instanceof Modifier.Volatile) {
mods |= ClassFileReader.ACC_VOLATILE;
} else if(m instanceof Modifier.Transient) {
mods |= ClassFileReader.ACC_TRANSIENT;
} else if(m instanceof Modifier.Synthetic) {
mods |= ClassFileReader.ACC_SYNTHETIC;
} else if(m instanceof Modifier.Enum) {
mods |= ClassFileReader.ACC_ENUM;
}
}
output.write_u16(mods);
}
protected void writeMethodModifiers(List<Modifier> modifiers)
throws IOException {
int mods = 0;
for(Modifier m : modifiers) {
if(m instanceof Modifier.Public) {
mods |= ClassFileReader.ACC_PUBLIC;
} else if(m instanceof Modifier.Private) {
mods |= ClassFileReader.ACC_PRIVATE;
} else if(m instanceof Modifier.Protected) {
mods |= ClassFileReader.ACC_PROTECTED;
} else if(m instanceof Modifier.Static) {
mods |= ClassFileReader.ACC_STATIC;
} else if(m instanceof Modifier.Final) {
mods |= ClassFileReader.ACC_FINAL;
} else if(m instanceof Modifier.Volatile) {
mods |= ClassFileReader.ACC_VOLATILE;
} else if(m instanceof Modifier.Synchronized) {
mods |= ClassFileReader.ACC_SYNCHRONIZED;
} else if(m instanceof Modifier.Bridge) {
mods |= ClassFileReader.ACC_BRIDGE;
} else if(m instanceof Modifier.VarArgs) {
mods |= ClassFileReader.ACC_VARARGS;
} else if(m instanceof Modifier.Native) {
mods |= ClassFileReader.ACC_NATIVE;
} else if(m instanceof Modifier.Abstract) {
mods |= ClassFileReader.ACC_ABSTRACT;
} else if(m instanceof Modifier.Synthetic) {
mods |= ClassFileReader.ACC_SYNTHETIC;
} else if(m instanceof Modifier.StrictFP) {
mods |= ClassFileReader.ACC_STRICT;
}
}
output.write_u16(mods);
}
protected static void writeModifiers(List<Modifier> modifiers, int[] masks,
Modifier[] mods, BinaryOutputStream output) throws IOException {
ArrayList<Modifier> r = new ArrayList<Modifier>();
int mask = 0;
for (Modifier m : modifiers) {
for (int i = 0; i != mods.length; ++i) {
if (mods[i].getClass().equals(m.getClass())) {
mask |= masks[i];
}
}
}
output.write_u16(mask);
}
}