/******************************************************************************* * Copyright (c) 2002,2006 IBM Corporation. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package x10.sncode; import java.io.PrintStream; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import x10.sncode.Container.Mapper; public class SnFile implements SnConstants { /** The constant pool */ private ConstantPool cp; /** Sn file major version. */ int majorVersion; /** Sn file minor version. */ int minorVersion; /** The contents. */ Tree.Branch tree; /** * Create a blank Sn editor with no members. */ public SnFile() { cp = new ConstantPool(); majorVersion = MAJOR; minorVersion = MINOR; tree = new Tree.Branch("Sn"); } public int getMajorVersion() { return majorVersion; } public int getMinorVersion() { return majorVersion; } /** * Set the class file format major version. You probably don't want to use * this unless you really know what you are doing. */ public void setMajorVersion(int major) { if (major < 0 || major > 0xFFFF) { throw new IllegalArgumentException("Major version out of range: " + major); } majorVersion = major; } /** * Set the class file format minor version. You probably don't want to use * this unless you really know what you are doing. */ public void setMinorVersion(int minor) { if (minor < 0 || minor > 0xFFFF) { throw new IllegalArgumentException("Major version out of range: " + minor); } minorVersion = minor; } public void addClass(ClassEditor e) { Tree t = e.makeTree(); tree.add(t); } public List<ClassEditor> classes() throws InvalidClassFileException { return Container.mapList(tree.findAll("Class"), new Mapper<Tree, ClassEditor, InvalidClassFileException>() { @Override ClassEditor map(Tree s) throws InvalidClassFileException { ClassEditor e = new ClassEditor(); e.readFrom(SnFile.this, s); return e; } }); } public void readFrom(ByteBuffer p) throws InvalidClassFileException { p.seek(0); int magic = p.getInt(); if (magic != SnConstants.MAGIC) throw new InvalidClassFileException(p.offset() - 4, "bad magic number 0x" + Integer.toHexString(magic)); int major = p.getUShort(); int minor = p.getUShort(); if (major != MAJOR && minor != MINOR) throw new InvalidClassFileException(p.offset() - 4, "bad version; got " + major + "." + minor + ", expected " + MAJOR + "." + MINOR); int count = p.getCount(); cp = new ConstantPool(); ByteBuffer p2 = new ByteBuffer(p.getBytes()); p2.seek(p.offset()); ConstantPoolParser cpp = new ConstantPoolParser(p2, count); p.seek(p2.offset()); cp.setRawCP(cpp); Tree t = Tree.readFrom(this, p); if (t instanceof Tree.Branch) tree = (Tree.Branch) t; else throw new InvalidClassFileException(p.offset(), "bad tree"); } public void writeInto(ByteBuffer w) { w.seek(0); w.addInt(SnConstants.MAGIC); w.addUShort(majorVersion); w.addUShort(minorVersion); Tree tree = this.tree; if (tree == null) tree = new Tree.Branch("Sn"); // Output the tree into a separate buffer. This will update the CP. ByteBuffer tw = new ByteBuffer(); tree.writeInto(this, tw); // Now, write the CP. int beforeCP = w.offset(); cp.copyInto(w); // The constant pool can grow during emission, so seek back to store the // size. w.setInt(beforeCP, cp.cpItems.size()); // And finally write the tree. w.addBytes(tw.getBytes()); } /** * After you've added everything you need to the class, call this method to * generate the actual class file data. This can only be called once. */ public byte[] makeBytes() { ByteBuffer w = new ByteBuffer(1024); writeInto(w); return w.getBytes(); } static <T> List<T> toList(Object l) { if (l instanceof List) return (List<T>) l; if (l instanceof Object[]) { return (List<T>) Arrays.asList((Object[]) l); } else throw new IllegalArgumentException(); } static <T> ArrayList<T> nonnull(List<T> l) { if (l == null) return new ArrayList<T>(0); else if (l instanceof ArrayList) return (ArrayList<T>) l; else return new ArrayList<T>(l); } public Tree.Branch tree() { return tree; } public void setCp(ConstantPool cp) { this.cp = cp; } public ConstantPool getConstantPool() { return cp; } public void dump(PrintStream out) { out.println("major: " + majorVersion); out.println("minor: " + minorVersion); out.println("constant pool:"); cp.dump(out); out.println("tree:"); tree.dump(out); out.println(); } }