package x10.sncode; import java.io.InvalidClassException; import java.io.PrintStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; public abstract class Tree { String key; public Tree(String key) { this.key = key; } public String getKey() { return key; } public boolean contains(String string) { Tree t = findTree(key); return t != null; } public Object find(String key) { Tree t = findTree(key); if (t != null) return t.getValue(); return null; } public Tree findTree(String key) { for (Tree t : getChildren()) { if (key.equals(t.key)) return t; } return null; } public List<Tree> findAll(String key) { List<Tree> ts = new ArrayList<Tree>(); for (Tree t : getChildren()) { if (key.equals(t.key)) ts.add(t); } return ts; } public abstract Object getValue(); public abstract List<Tree> getChildren(); public abstract void writeInto(SnFile sn, ByteBuffer buf); public void dump(PrintStream out) { dump(out, 0); } public abstract void dump(PrintStream out, int indent); public static Tree readFrom(SnFile sn, ByteBuffer buf) throws InvalidClassFileException { // for debugging int offset = buf.offset(); int magic = buf.getInt(); assert magic == 0xdefaced; int dataLen = buf.getLength(); try { if (dataLen == -1) { int keyIndex = buf.getCPIndex(); int valIndex = buf.getCPIndex(); String key = sn.getConstantPool().getCPUtf8(keyIndex); Object value = sn.getConstantPool().getCPEntry(valIndex); return new Leaf(key, value); } else { int dataOffset = buf.offset(); int endOffset = dataOffset + dataLen; int keyIndex = buf.getCPIndex(); String key = sn.getConstantPool().getCPUtf8(keyIndex); List<Tree> children = new ArrayList<Tree>(); while (buf.offset() < endOffset) { Tree t = readFrom(sn, buf); children.add(t); } if (endOffset != buf.offset()) throw new InvalidClassFileException(offset, "bad attribute"); return new Branch(key, children); } } catch (ClassCastException e) { throw new InvalidClassFileException(offset, e.getMessage()); } } public static class Branch extends Tree { List<Tree> children; public Branch(String key) { super(key); children = new ArrayList<Tree>(0); } public Branch(String key, Tree... children) { this(key, Arrays.asList(children)); } public Branch(String key, List<Tree> children) { super(key); this.children = new ArrayList<Tree>(children); } public void add(Tree child) { children.add(child); } public void writeInto(SnFile sn, ByteBuffer buf) { buf.addInt(0xdefaced); int offset = buf.offset(); buf.addLength(0); buf.addCPIndex(sn.getConstantPool().addCPUtf8(key)); for (Tree e : getChildren()) { e.writeInto(sn, buf); } buf.setLength(offset, buf.offset() - offset - 4); } public List<Tree> getChildren() { return children; } public Object getValue() { return null; } public String toString() { StringBuilder sb = new StringBuilder(); sb.append("("); sb.append(key); sb.append(" "); for (Tree t : getChildren()) { sb.append(" "); sb.append(t); } sb.append(")"); return sb.toString(); } @Override public void dump(PrintStream out, int indent) { indent(out, indent); out.print("("); out.print(key); for (int i = 0; i < children.size(); i++) { Tree t = children.get(i); out.println(); t.dump(out, indent + 1); } out.print(")"); } } public static class Leaf extends Tree { Object value; public Leaf(String key, Object value) { super(key); this.value = value; } public Object getValue() { return value; } public void writeInto(SnFile sn, ByteBuffer buf) { buf.addInt(0xdefaced); buf.addLength(-1); buf.addInt(sn.getConstantPool().addCPUtf8(key)); buf.addInt(sn.getConstantPool().addCPEntry(value)); } public List<Tree> getChildren() { return Collections.EMPTY_LIST; } public String toString() { StringBuilder sb = new StringBuilder(); sb.append(key); sb.append(": "); sb.append(value); return sb.toString(); } @Override public void dump(PrintStream out, int indent) { indent(out, indent); out.print("("); out.print(key); out.print(": "); if (value instanceof Object[]) out.print(Arrays.asList((Object[]) value)); else out.print(value); out.print(")"); } } public static void indent(PrintStream out, int indent) { for (int i = 0; i < indent; i++) { out.print(" "); } } }