Index: src/main/java/org/apache/harmony/pack200/AttributeLayout.java =================================================================== --- src/main/java/org/apache/harmony/pack200/AttributeLayout.java (revision 571408) +++ src/main/java/org/apache/harmony/pack200/AttributeLayout.java (working copy) @@ -22,8 +22,12 @@ // NOTE: Also, don't get rid of 'else' statements for the hell of it ... import org.apache.harmony.pack200.Segment.SegmentConstantPool; -public class AttributeLayout { +public class AttributeLayout implements IMatcher { static class Key { + private final int context; + + private final String name; + public Key(String name, int context) throws Pack200Exception { if (name == null || name.length() == 0) throw new Pack200Exception("Cannot have an unnamed layout"); @@ -36,20 +40,6 @@ } - private int context; - - private String name; - - - public int hashCode() { - final int PRIME = 31; - int result = 1; - result = PRIME * result + context; - result = PRIME * result + ((name == null) ? 0 : name.hashCode()); - return result; - } - - public boolean equals(Object obj) { if (this == obj) return true; @@ -68,6 +58,14 @@ return true; } + public int hashCode() { + final int PRIME = 31; + int result = 1; + result = PRIME * result + context; + result = PRIME * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + public String toString() { return contextNames[context] + ": " + name; } @@ -74,100 +72,44 @@ } - private String layout; - - Key key; - - private long mask; - - public static final String ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS = "RuntimeInvisibleAnnotations"; - - public static final String ATTRIBUTE_CLASS_FILE_VERSION = "class-file version"; - - public static final String ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS = "RuntimeInvisibleParameterAnnotations"; - - public static final String ATTRIBUTE_ANNOTATION_DEFAULT = "AnnotationDefault"; - - public static final String ATTRIBUTE_CODE = "Code"; - - public static final String ATTRIBUTE_SOURCE_FILE = "SourceFile"; - - public static final String ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE = "LocalVariableTypeTable"; - - public static final String ATTRIBUTE_LOCAL_VARIABLE_TABLE = "LocalVariableTable"; - - public static final String ATTRIBUTE_LINE_NUMBER_TABLE = "LineNumberTable"; - - public static final String ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS = "RuntimeVisibleParameterAnnotations"; - - public static final String ATTRIBUTE_INNER_CLASSES = "InnerClasses"; - - public static final String ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS = "RuntimeVisibleAnnotations"; - - public static final String ATTRIBUTE_DEPRECATED = "Deprecated"; - - public static final String ATTRIBUTE_CONSTANT_VALUE = "ConstantValue"; - - public static final String ATTRIBUTE_ENCLOSING_METHOD = "EnclosingMethod"; - - public static final String ATTRIBUTE_EXCEPTIONS = "Exceptions"; - - public static final String ATTRIBUTE_SIGNATURE = "Signature"; - - public static final int CONTEXT_CODE = 1 << 4; - + public static final String ACC_ABSTRACT = "ACC_ABSTRACT"; //$NON-NLS-1$ + public static final String ACC_ANNOTATION = "ACC_ANNOTATION"; //$NON-NLS-1$ + public static final String ACC_ENUM = "ACC_ENUM"; //$NON-NLS-1$ + public static final String ACC_FINAL = "ACC_FINAL"; //$NON-NLS-1$ + public static final String ACC_INTERFACE = "ACC_INTERFACE"; //$NON-NLS-1$ + public static final String ACC_NATIVE = "ACC_NATIVE"; //$NON-NLS-1$ + public static final String ACC_PRIVATE = "ACC_PRIVATE"; //$NON-NLS-1$ + public static final String ACC_PROTECTED = "ACC_PROTECTED"; //$NON-NLS-1$ + public static final String ACC_PUBLIC = "ACC_PUBLIC"; //$NON-NLS-1$ + public static final String ACC_STATIC = "ACC_STATIC"; //$NON-NLS-1$ + public static final String ACC_STRICT = "ACC_STRICT"; //$NON-NLS-1$ + public static final String ACC_SYNCHRONIZED = "ACC_SYNCHRONIZED"; //$NON-NLS-1$ + public static final String ACC_SYNTHETIC = "ACC_SYNTHETIC"; //$NON-NLS-1$ + public static final String ACC_TRANSIENT = "ACC_TRANSIENT"; //$NON-NLS-1$ + public static final String ACC_VOLATILE = "ACC_VOLATILE"; //$NON-NLS-1$ + public static final String ATTRIBUTE_ANNOTATION_DEFAULT = "AnnotationDefault"; //$NON-NLS-1$ + public static final String ATTRIBUTE_CLASS_FILE_VERSION = "class-file version"; //$NON-NLS-1$ + public static final String ATTRIBUTE_CODE = "Code"; //$NON-NLS-1$ + public static final String ATTRIBUTE_CONSTANT_VALUE = "ConstantValue"; //$NON-NLS-1$ + public static final String ATTRIBUTE_DEPRECATED = "Deprecated"; //$NON-NLS-1$ + public static final String ATTRIBUTE_ENCLOSING_METHOD = "EnclosingMethod"; //$NON-NLS-1$ + public static final String ATTRIBUTE_EXCEPTIONS = "Exceptions"; //$NON-NLS-1$ + public static final String ATTRIBUTE_INNER_CLASSES = "InnerClasses"; //$NON-NLS-1$ + public static final String ATTRIBUTE_LINE_NUMBER_TABLE = "LineNumberTable"; //$NON-NLS-1$ + public static final String ATTRIBUTE_LOCAL_VARIABLE_TABLE = "LocalVariableTable"; //$NON-NLS-1$ + public static final String ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE = "LocalVariableTypeTable"; //$NON-NLS-1$ + public static final String ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS = "RuntimeInvisibleAnnotations"; //$NON-NLS-1$ + public static final String ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS = "RuntimeInvisibleParameterAnnotations"; //$NON-NLS-1$ + public static final String ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS = "RuntimeVisibleAnnotations"; //$NON-NLS-1$ + public static final String ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS = "RuntimeVisibleParameterAnnotations"; //$NON-NLS-1$ + public static final String ATTRIBUTE_SIGNATURE = "Signature"; //$NON-NLS-1$ + public static final String ATTRIBUTE_SOURCE_FILE = "SourceFile"; //$NON-NLS-1$ public static final int CONTEXT_CLASS = 1 << 0; - + public static final int CONTEXT_CODE = 1 << 4; public static final int CONTEXT_FIELD = 1 << 2; - public static final int CONTEXT_METHOD = 1 << 3; - - private static final String[] contextNames = { "Class", "Field", "Method", - "Code", }; - - public Codec getCodec() { - if (layout.indexOf("O") >= 0) { - return Codec.BRANCH5; - } else if (layout.indexOf("P") >= 0) { - return Codec.BCI5; - } else if (layout.indexOf("S") >= 0 && layout.indexOf("KS") < 0 - && layout.indexOf("RS") < 0) { - return Codec.SIGNED5; - } else if (layout.indexOf("B") >= 0) { - return Codec.BYTE1; - } - /* - * TODO Add this as a test (and don't commit since this is copyright - * text) && ) If the layout contains 'O', use BRANCH5. Otherwise, if the - * layout contains 'P', use BCI5. Otherwise, if the layout contains 'S' - * but not 'KS' or 'RS', use SIGNED5. Otherwise, if the layout contains - * 'B', use BYTE1. For all other layouts use UNSIGNED5. - */ - else { - return Codec.UNSIGNED5; - } - } - - public Object getValue(long value, String type, Segment segment) - throws Pack200Exception { - // TODO This really needs to be better tested, esp. the different types - // TODO This should have the ability to deal with RUN stuff too, and unions - if (layout.startsWith("KQ")) { - if (type.equals("Ljava/lang/String;")) { - Object value2 = getValue("KS", value, segment); - return value2; - } else { - return getValue("K" + type + layout.substring(2), value, - segment); - } - } else { - return getValue(layout, value, segment); - } - } - - public Object getValue(long value, Segment segment) throws Pack200Exception { - return getValue(layout, value, segment); - } + private static final String[] contextNames = { "Class", "Field", "Method", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + "Code", }; //$NON-NLS-1$ private static Object getValue(String layout, long value, Segment segment) throws Pack200Exception { @@ -172,16 +114,16 @@ private static Object getValue(String layout, long value, Segment segment) throws Pack200Exception { SegmentConstantPool pool = segment.getConstantPool(); - if (layout.startsWith("R")) { + if (layout.startsWith("R")) { //$NON-NLS-1$ // references if (layout.indexOf('N') != -1) value--; - if (layout.startsWith("RU")) { + if (layout.startsWith("RU")) { //$NON-NLS-1$ return pool.getValue(SegmentConstantPool.UTF_8, value); - } else if (layout.startsWith("RS")) { + } else if (layout.startsWith("RS")) { //$NON-NLS-1$ return pool.getValue(SegmentConstantPool.SIGNATURE, value); } - } else if (layout.startsWith("K")) { + } else if (layout.startsWith("K")) { //$NON-NLS-1$ char type = layout.charAt(1); switch (type) { case 'S': // String @@ -192,9 +134,9 @@ case 'F': // Float return pool.getValue(SegmentConstantPool.CP_FLOAT, value); case 'J': // Long - return pool.getValue(SegmentConstantPool.CP_LONG,value); + return pool.getValue(SegmentConstantPool.CP_LONG, value); case 'D': // Double - return pool.getValue(SegmentConstantPool.CP_DOUBLE,value); + return pool.getValue(SegmentConstantPool.CP_DOUBLE, value); } } throw new Pack200Exception("Unknown layout encoding: " + layout); @@ -200,6 +142,12 @@ throw new Pack200Exception("Unknown layout encoding: " + layout); } + Key key; + + private final String layout; + + private long mask; + public AttributeLayout(String name, int context, String layout, int index) throws Pack200Exception { super(); @@ -214,31 +162,6 @@ this.layout = layout; } - public boolean isCode() { - return key.context == CONTEXT_CODE; - } - - public boolean isClass() { - return key.context == CONTEXT_CLASS; - } - - public boolean isMethod() { - return key.context == CONTEXT_METHOD; - } - - public boolean isField() { - return key.context == CONTEXT_FIELD; - } - - public int hashCode() { - return key.hashCode(); - } - - public boolean matches(long value) { - return (value & mask) != 0; - } - - public boolean equals(Object obj) { if (this == obj) return true; @@ -260,8 +183,27 @@ return true; } - public String toString() { - return key.toString(); + public Codec getCodec() { + if (layout.indexOf("O") >= 0) { //$NON-NLS-1$ + return Codec.BRANCH5; + } else if (layout.indexOf("P") >= 0) { //$NON-NLS-1$ + return Codec.BCI5; + } else if (layout.indexOf("S") >= 0 && layout.indexOf("KS") < 0 //$NON-NLS-1$ //$NON-NLS-2$ + && layout.indexOf("RS") < 0) { //$NON-NLS-1$ + return Codec.SIGNED5; + } else if (layout.indexOf("B") >= 0) { //$NON-NLS-1$ + return Codec.BYTE1; + } + /* + * TODO Add this as a test (and don't commit since this is copyright + * text) && ) If the layout contains 'O', use BRANCH5. Otherwise, if the + * layout contains 'P', use BCI5. Otherwise, if the layout contains 'S' + * but not 'KS' or 'RS', use SIGNED5. Otherwise, if the layout contains + * 'B', use BYTE1. For all other layouts use UNSIGNED5. + */ + else { + return Codec.UNSIGNED5; + } } public String getLayout() { @@ -268,4 +210,57 @@ return layout; } + public Object getValue(long value, Segment segment) throws Pack200Exception { + return getValue(layout, value, segment); + } + + public Object getValue(long value, String type, Segment segment) + throws Pack200Exception { + // TODO This really needs to be better tested, esp. the different types + // TODO This should have the ability to deal with RUN stuff too, and + // unions + if (layout.startsWith("KQ")) { //$NON-NLS-1$ + if (type.equals("Ljava/lang/String;")) { //$NON-NLS-1$ + Object value2 = getValue("KS", value, segment); //$NON-NLS-1$ + return value2; + } else { + return getValue("K" + type + layout.substring(2), value, //$NON-NLS-1$ + segment); + } + } else { + return getValue(layout, value, segment); + } + } + + public int hashCode() { + return key.hashCode(); + } + + public boolean isClass() { + return key.context == CONTEXT_CLASS; + } + + public boolean isCode() { + return key.context == CONTEXT_CODE; + } + + public boolean isField() { + return key.context == CONTEXT_FIELD; + } + + public boolean isMethod() { + return key.context == CONTEXT_METHOD; + } + + /* (non-Javadoc) + * @see org.apache.harmony.pack200.IMatches#matches(long) + */ + public boolean matches(long value) { + return (value & mask) != 0; + } + + public String toString() { + return key.toString(); + } + } Index: src/main/java/org/apache/harmony/pack200/AttributeLayoutMap.java =================================================================== --- src/main/java/org/apache/harmony/pack200/AttributeLayoutMap.java (revision 571408) +++ src/main/java/org/apache/harmony/pack200/AttributeLayoutMap.java (working copy) @@ -15,9 +15,11 @@ * limitations under the License. */ package org.apache.harmony.pack200; -//NOTE: Do not use generics in this code; it needs to run on JVMs < 1.5 -//NOTE: Do not extract strings as messages; this code is still a work-in-progress -//NOTE: Also, don't get rid of 'else' statements for the hell of it ... + +// NOTE: Do not use generics in this code; it needs to run on JVMs < 1.5 +// NOTE: Do not extract strings as messages; this code is still a +// work-in-progress +// NOTE: Also, don't get rid of 'else' statements for the hell of it ... import java.util.HashMap; import java.util.Map; @@ -31,12 +33,108 @@ private static AttributeLayout[] getDefaultAttributeLayouts() throws Pack200Exception { return new AttributeLayout[] { - new AttributeLayout(AttributeLayout.ATTRIBUTE_LINE_NUMBER_TABLE, + new AttributeLayout(AttributeLayout.ACC_PUBLIC, + AttributeLayout.CONTEXT_CLASS, "", 0), + new AttributeLayout(AttributeLayout.ACC_PUBLIC, + AttributeLayout.CONTEXT_FIELD, "", 0), + new AttributeLayout(AttributeLayout.ACC_PUBLIC, + AttributeLayout.CONTEXT_METHOD, "", 0), + new AttributeLayout(AttributeLayout.ACC_PRIVATE, + AttributeLayout.CONTEXT_CLASS, "", 1), + new AttributeLayout(AttributeLayout.ACC_PRIVATE, + AttributeLayout.CONTEXT_FIELD, "", 1), + new AttributeLayout(AttributeLayout.ACC_PRIVATE, + AttributeLayout.CONTEXT_METHOD, "", 1), + new AttributeLayout( + AttributeLayout.ATTRIBUTE_LINE_NUMBER_TABLE, AttributeLayout.CONTEXT_CODE, "NH[PHH]", 1), - new AttributeLayout(AttributeLayout.ATTRIBUTE_LOCAL_VARIABLE_TABLE, + + new AttributeLayout(AttributeLayout.ACC_PROTECTED, + AttributeLayout.CONTEXT_CLASS, "", 2), + new AttributeLayout(AttributeLayout.ACC_PROTECTED, + AttributeLayout.CONTEXT_FIELD, "", 2), + new AttributeLayout(AttributeLayout.ACC_PROTECTED, + AttributeLayout.CONTEXT_METHOD, "", 2), + new AttributeLayout( + AttributeLayout.ATTRIBUTE_LOCAL_VARIABLE_TABLE, AttributeLayout.CONTEXT_CODE, "NH[PHOHRUHRSHH]", 2), - new AttributeLayout(AttributeLayout.ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE, + + new AttributeLayout(AttributeLayout.ACC_STATIC, + AttributeLayout.CONTEXT_CLASS, "", 3), + new AttributeLayout(AttributeLayout.ACC_STATIC, + AttributeLayout.CONTEXT_FIELD, "", 3), + new AttributeLayout(AttributeLayout.ACC_STATIC, + AttributeLayout.CONTEXT_METHOD, "", 3), + new AttributeLayout( + AttributeLayout.ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE, AttributeLayout.CONTEXT_CODE, "NH[PHOHRUHRSHH]", 3), + + new AttributeLayout(AttributeLayout.ACC_FINAL, + AttributeLayout.CONTEXT_CLASS, "", 4), + new AttributeLayout(AttributeLayout.ACC_FINAL, + AttributeLayout.CONTEXT_FIELD, "", 4), + new AttributeLayout(AttributeLayout.ACC_FINAL, + AttributeLayout.CONTEXT_METHOD, "", 4), + new AttributeLayout(AttributeLayout.ACC_SYNCHRONIZED, + AttributeLayout.CONTEXT_CLASS, "", 5), + new AttributeLayout(AttributeLayout.ACC_SYNCHRONIZED, + AttributeLayout.CONTEXT_FIELD, "", 5), + new AttributeLayout(AttributeLayout.ACC_SYNCHRONIZED, + AttributeLayout.CONTEXT_METHOD, "", 5), + new AttributeLayout(AttributeLayout.ACC_VOLATILE, + AttributeLayout.CONTEXT_CLASS, "", 6), + new AttributeLayout(AttributeLayout.ACC_VOLATILE, + AttributeLayout.CONTEXT_FIELD, "", 6), + new AttributeLayout(AttributeLayout.ACC_VOLATILE, + AttributeLayout.CONTEXT_METHOD, "", 6), + new AttributeLayout(AttributeLayout.ACC_TRANSIENT, + AttributeLayout.CONTEXT_CLASS, "", 7), + new AttributeLayout(AttributeLayout.ACC_TRANSIENT, + AttributeLayout.CONTEXT_FIELD, "", 7), + new AttributeLayout(AttributeLayout.ACC_TRANSIENT, + AttributeLayout.CONTEXT_METHOD, "", 7), + new AttributeLayout(AttributeLayout.ACC_NATIVE, + AttributeLayout.CONTEXT_CLASS, "", 8), + new AttributeLayout(AttributeLayout.ACC_NATIVE, + AttributeLayout.CONTEXT_FIELD, "", 8), + new AttributeLayout(AttributeLayout.ACC_NATIVE, + AttributeLayout.CONTEXT_METHOD, "", 8), + new AttributeLayout(AttributeLayout.ACC_INTERFACE, + AttributeLayout.CONTEXT_CLASS, "", 9), + new AttributeLayout(AttributeLayout.ACC_INTERFACE, + AttributeLayout.CONTEXT_FIELD, "", 9), + new AttributeLayout(AttributeLayout.ACC_INTERFACE, + AttributeLayout.CONTEXT_METHOD, "", 9), + new AttributeLayout(AttributeLayout.ACC_ABSTRACT, + AttributeLayout.CONTEXT_CLASS, "", 10), + new AttributeLayout(AttributeLayout.ACC_ABSTRACT, + AttributeLayout.CONTEXT_FIELD, "", 10), + new AttributeLayout(AttributeLayout.ACC_ABSTRACT, + AttributeLayout.CONTEXT_METHOD, "", 10), + new AttributeLayout(AttributeLayout.ACC_STRICT, + AttributeLayout.CONTEXT_CLASS, "", 11), + new AttributeLayout(AttributeLayout.ACC_STRICT, + AttributeLayout.CONTEXT_FIELD, "", 11), + new AttributeLayout(AttributeLayout.ACC_STRICT, + AttributeLayout.CONTEXT_METHOD, "", 11), + new AttributeLayout(AttributeLayout.ACC_SYNTHETIC, + AttributeLayout.CONTEXT_CLASS, "", 12), + new AttributeLayout(AttributeLayout.ACC_SYNTHETIC, + AttributeLayout.CONTEXT_FIELD, "", 12), + new AttributeLayout(AttributeLayout.ACC_SYNTHETIC, + AttributeLayout.CONTEXT_METHOD, "", 12), + new AttributeLayout(AttributeLayout.ACC_ANNOTATION, + AttributeLayout.CONTEXT_CLASS, "", 13), + new AttributeLayout(AttributeLayout.ACC_ANNOTATION, + AttributeLayout.CONTEXT_FIELD, "", 13), + new AttributeLayout(AttributeLayout.ACC_ANNOTATION, + AttributeLayout.CONTEXT_METHOD, "", 13), + new AttributeLayout(AttributeLayout.ACC_ENUM, + AttributeLayout.CONTEXT_CLASS, "", 14), + new AttributeLayout(AttributeLayout.ACC_ENUM, + AttributeLayout.CONTEXT_FIELD, "", 14), + new AttributeLayout(AttributeLayout.ACC_ENUM, + AttributeLayout.CONTEXT_METHOD, "", 14), new AttributeLayout(AttributeLayout.ATTRIBUTE_SOURCE_FILE, AttributeLayout.CONTEXT_CLASS, "RUNH", 17), new AttributeLayout(AttributeLayout.ATTRIBUTE_CONSTANT_VALUE, @@ -41,8 +139,8 @@ AttributeLayout.CONTEXT_CLASS, "RUNH", 17), new AttributeLayout(AttributeLayout.ATTRIBUTE_CONSTANT_VALUE, AttributeLayout.CONTEXT_FIELD, "KQH", 17), - new AttributeLayout(AttributeLayout.ATTRIBUTE_CODE, AttributeLayout.CONTEXT_METHOD, - "*", 17), + new AttributeLayout(AttributeLayout.ATTRIBUTE_CODE, + AttributeLayout.CONTEXT_METHOD, "*", 17), new AttributeLayout(AttributeLayout.ATTRIBUTE_ENCLOSING_METHOD, AttributeLayout.CONTEXT_CLASS, "RCHRDNH", 18), new AttributeLayout(AttributeLayout.ATTRIBUTE_EXCEPTIONS, @@ -47,10 +145,10 @@ AttributeLayout.CONTEXT_CLASS, "RCHRDNH", 18), new AttributeLayout(AttributeLayout.ATTRIBUTE_EXCEPTIONS, AttributeLayout.CONTEXT_METHOD, "NH[RCH]", 18), - new AttributeLayout(AttributeLayout.ATTRIBUTE_SIGNATURE, AttributeLayout.CONTEXT_CLASS, - "RSH", 19), - new AttributeLayout(AttributeLayout.ATTRIBUTE_SIGNATURE, AttributeLayout.CONTEXT_FIELD, - "RSH", 19), + new AttributeLayout(AttributeLayout.ATTRIBUTE_SIGNATURE, + AttributeLayout.CONTEXT_CLASS, "RSH", 19), + new AttributeLayout(AttributeLayout.ATTRIBUTE_SIGNATURE, + AttributeLayout.CONTEXT_FIELD, "RSH", 19), new AttributeLayout(AttributeLayout.ATTRIBUTE_SIGNATURE, AttributeLayout.CONTEXT_METHOD, "RSH", 19), new AttributeLayout(AttributeLayout.ATTRIBUTE_DEPRECATED, @@ -59,31 +157,41 @@ AttributeLayout.CONTEXT_FIELD, "", 20), new AttributeLayout(AttributeLayout.ATTRIBUTE_DEPRECATED, AttributeLayout.CONTEXT_METHOD, "", 20), - new AttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS, + new AttributeLayout( + AttributeLayout.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_CLASS, "*", 21), - new AttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS, + new AttributeLayout( + AttributeLayout.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_FIELD, "*", 21), - new AttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS, + new AttributeLayout( + AttributeLayout.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_METHOD, "*", 21), - new AttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS, + new AttributeLayout( + AttributeLayout.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_CLASS, "*", 22), - new AttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS, + new AttributeLayout( + AttributeLayout.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_FIELD, "*", 22), - new AttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS, + new AttributeLayout( + AttributeLayout.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS, AttributeLayout.CONTEXT_METHOD, "*", 22), new AttributeLayout(AttributeLayout.ATTRIBUTE_INNER_CLASSES, AttributeLayout.CONTEXT_CLASS, "*", 23), - new AttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS, + new AttributeLayout( + AttributeLayout.ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS, AttributeLayout.CONTEXT_METHOD, "*", 23), - new AttributeLayout(AttributeLayout.ATTRIBUTE_CLASS_FILE_VERSION, + new AttributeLayout( + AttributeLayout.ATTRIBUTE_CLASS_FILE_VERSION, AttributeLayout.CONTEXT_CLASS, "*", 24), - new AttributeLayout(AttributeLayout.ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS, + new AttributeLayout( + AttributeLayout.ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS, AttributeLayout.CONTEXT_METHOD, "*", 24), - new AttributeLayout(AttributeLayout.ATTRIBUTE_ANNOTATION_DEFAULT, + new AttributeLayout( + AttributeLayout.ATTRIBUTE_ANNOTATION_DEFAULT, AttributeLayout.CONTEXT_METHOD, "*", 25) }; } - private Map layouts; + private final Map layouts; public AttributeLayoutMap() throws Pack200Exception { this.layouts = new HashMap(); Index: src/main/java/org/apache/harmony/pack200/Segment.java =================================================================== --- src/main/java/org/apache/harmony/pack200/Segment.java (revision 571408) +++ src/main/java/org/apache/harmony/pack200/Segment.java (working copy) @@ -20,7 +20,9 @@ // NOTE: Do not extract strings as messages; this code is still a // work-in-progress // NOTE: Also, don't get rid of 'else' statements for the hell of it ... +import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.EOFException; import java.io.IOException; @@ -26,7 +28,6 @@ import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; -import java.util.Arrays; import java.util.jar.JarEntry; import java.util.jar.JarOutputStream; import java.util.zip.GZIPInputStream; @@ -32,6 +33,7 @@ import java.util.zip.GZIPInputStream; import org.apache.harmony.pack200.bytecode.Attribute; +import org.apache.harmony.pack200.bytecode.ByteCode; import org.apache.harmony.pack200.bytecode.CPClass; import org.apache.harmony.pack200.bytecode.CPField; import org.apache.harmony.pack200.bytecode.CPMethod; @@ -38,6 +40,7 @@ import org.apache.harmony.pack200.bytecode.ClassConstantPool; import org.apache.harmony.pack200.bytecode.ClassFile; import org.apache.harmony.pack200.bytecode.ClassFileEntry; +import org.apache.harmony.pack200.bytecode.CodeAttribute; import org.apache.harmony.pack200.bytecode.ConstantValueAttribute; import org.apache.harmony.pack200.bytecode.ExceptionsAttribute; import org.apache.harmony.pack200.bytecode.SourceFileAttribute; @@ -147,15 +150,17 @@ Pack200Exception { Segment segment = new Segment(); // See if file is GZip compressed - if (in.markSupported()) { - in.mark(2); - if (((in.read() & 0xFF) | (in.read() & 0xFF) << 8) == GZIPInputStream.GZIP_MAGIC) { - in.reset(); - in = new GZIPInputStream(in); - } else { - in.reset(); - } - + if (!in.markSupported()) { + in = new BufferedInputStream(in); + if (!in.markSupported()) + throw new IllegalStateException(); + } + in.mark(2); + if (((in.read() & 0xFF) | (in.read() & 0xFF) << 8) == GZIPInputStream.GZIP_MAGIC) { + in.reset(); + in = new BufferedInputStream(new GZIPInputStream(in)); + } else { + in.reset(); } segment.parseSegment(in); return segment; @@ -228,6 +233,12 @@ private String[] classThis; + private int[] codeHandlerCount; + + private int[] codeMaxNALocals; + + private int[] codeMaxStack; + private String[] cpClass; private int cpClassCount; @@ -318,6 +329,8 @@ private ArrayList[][] methodAttributes; + private byte[][][] methodByteCodePacked; + private String[][] methodDescr; private ExceptionsAttribute[][] methodExceptions; @@ -332,7 +345,7 @@ private int segmentsRemaining; - private ClassFile buildClassFile(int classNum) { + private ClassFile buildClassFile(int classNum) throws Pack200Exception { ClassFile classFile = new ClassFile(); classFile.major = defaultClassMajorVersion; // TODO If // classVersionMajor[] use @@ -347,9 +360,16 @@ int i = fullName.lastIndexOf("/") + 1; // if lastIndexOf==-1, then // -1+1=0, so str.substring(0) // == str - String fileName = fullName.substring(i) + ".java"; - classFile.attributes = new Attribute[] { (Attribute) cp - .add(new SourceFileAttribute(fileName)) }; + AttributeLayout SOURCE_FILE = attributeDefinitionMap + .getAttributeLayout(AttributeLayout.ATTRIBUTE_SOURCE_FILE, + AttributeLayout.CONTEXT_CLASS); + if (SOURCE_FILE.matches(classFlags[classNum])) { + String fileName = fullName.substring(i) + ".java"; + classFile.attributes = new Attribute[] { (Attribute) cp + .add(new SourceFileAttribute(fileName)) }; + } else { + classFile.attributes = new Attribute[] {}; + } // this/superclass ClassFileEntry cfThis = cp.add(new CPClass(fullName)); ClassFileEntry cfSuper = cp.add(new CPClass(classSuper[classNum])); @@ -467,15 +487,15 @@ */ private long[] decodeBandLong(String name, InputStream in, BHSDCodec codec, int count) throws IOException, Pack200Exception { + in.mark(count * codec.getB()); long[] result = codec.decode(count, in); - if (result.length > 0) { + if (result.length > 0 && !codec.equals(Codec.BYTE1)) { int first = (int) result[0]; if (codec.isSigned() && first >= -256 && first <= -1) { - // TODO Well, switch codecs then ... Codec weShouldHaveUsed = CodecEncoding.getCodec(-1 - first, getBandHeadersInputStream(), codec); - throw new Error("Bugger. We should have switched codec to " - + weShouldHaveUsed); + in.reset(); + result = weShouldHaveUsed.decode(count, in); } else if (!codec.isSigned() && first >= codec.getL() && first <= codec.getL() + 255) { Codec weShouldHaveUsed = CodecEncoding.getCodec(first @@ -480,9 +500,8 @@ && first <= codec.getL() + 255) { Codec weShouldHaveUsed = CodecEncoding.getCodec(first - codec.getL(), getBandHeadersInputStream(), codec); - // TODO Well, switch codecs then ... - throw new Error("Bugger. We should have switched codec to " - + weShouldHaveUsed); + in.reset(); + result = weShouldHaveUsed.decode(count, in); } } // TODO Remove debugging code @@ -653,6 +672,7 @@ for (int j = 0; j < methodFlags[i].length; j++) { long flag = methodFlags[i][j]; if (layout.matches(flag)) { + // TODO This should be a decoeBand ... numExceptions[i][j] = (int) codec.decode(in); } } @@ -662,15 +682,17 @@ for (int j = 0; j < methodFlags[i].length; j++) { long flag = methodFlags[i][j]; int n = numExceptions[i][j]; - CPClass[] exceptions = new CPClass[n]; - if (layout.matches(flag)) { - for (int k = 0; k < n; k++) { - long result = codec.decode(in); - exceptions[k] = new CPClass(cpClass[(int) result]); + if (n > 0) { + CPClass[] exceptions = new CPClass[n]; + if (layout.matches(flag)) { + for (int k = 0; k < n; k++) { + long result = codec.decode(in); + exceptions[k] = new CPClass(cpClass[(int) result]); + } } + methodExceptions[i][j] = new ExceptionsAttribute(exceptions); + methodAttributes[i][j].add(methodExceptions[i][j]); } - methodExceptions[i][j] = new ExceptionsAttribute(exceptions); - methodAttributes[i][j].add(methodExceptions[i][j]); } } } @@ -695,17 +717,146 @@ debug("Parsing unknown attributes for " + name); AttributeLayout layout = attributeDefinitionMap.getAttributeLayout( name, context); - for (int i = 0; i < flags.length; i++) { - for (int j = 0; j < flags[i].length; j++) { - if (layout.matches(flags[i][j])) - throw new Error("We've got data for " + name - + " and we don't know what to do with it (yet)"); + int count = SegmentUtils.countMatches(flags, layout); + if (count > 0) + throw new Error("We've got data for " + name + + " and we don't know what to do with it (yet)"); + } + + private void parseBcBands(InputStream in) throws IOException, + Pack200Exception { + int bcStringRefCount = 0; + int bcInitRefCount = 0; + int bcFieldRefCount = 0; + int bcThisFieldCount = 0; + int bcMethodRefCount = 0; + int bcIMethodRefCount = 0; + + AttributeLayout abstractModifier = attributeDefinitionMap + .getAttributeLayout(AttributeLayout.ACC_ABSTRACT, + AttributeLayout.CONTEXT_METHOD); + AttributeLayout nativeModifier = attributeDefinitionMap + .getAttributeLayout(AttributeLayout.ACC_NATIVE, + AttributeLayout.CONTEXT_METHOD); + AttributeLayout staticModifier = attributeDefinitionMap + .getAttributeLayout(AttributeLayout.ACC_STATIC, + AttributeLayout.CONTEXT_METHOD); + methodByteCodePacked = new byte[classCount][][]; + int bcParsed = 0; + for (int c = 0; c < classCount; c++) { + int numberOfMethods = methodFlags[c].length; + methodByteCodePacked[c] = new byte[numberOfMethods][]; + for (int m = 0; m < numberOfMethods; m++) { + long methodFlag = methodFlags[c][m]; + if (!abstractModifier.matches(methodFlag) + && !nativeModifier.matches(methodFlag)) { + ByteArrayOutputStream codeBytes = new ByteArrayOutputStream(); + byte code; + while ((code = (byte) (0xff & in.read())) != -1) + codeBytes.write(code); + methodByteCodePacked[c][m] = codeBytes.toByteArray(); + bcParsed += methodByteCodePacked[c][m].length; + for (int i = 0; i < methodByteCodePacked[c][m].length; i++) { + int codePacked = 0xff & methodByteCodePacked[c][m][i]; + // TODO a lot of this needs to be encapsulated in the + // place that + // calculates what the arguments are, since (a) it will + // need + // to know where to get them, and (b) what to do with + // them + // once they've been gotten. But that's for another + // time. + switch (codePacked) { + case 18: // (a)ldc + bcStringRefCount++; + break; + case 178: // getstatic + case 179: // putstatic + case 180: // getfield + case 181: // putfield + bcFieldRefCount++; + break; + case 182: // invokevirtual + case 183: // invokespecial + case 184: // invokestatic + bcMethodRefCount++; + break; + case 185: // invokeinterface + bcIMethodRefCount++; + break; + case 202: // getstatic_this + case 203: // putstatic_this + case 204: // getfield_this + case 205: // putfield_this + bcThisFieldCount++; + break; + case 231: // invoke_special_init + bcInitRefCount++; + break; + + default: // unhandled specifically at this stage + debug("Found unhandled " + + ByteCode.getByteCode(codePacked)); + } + } + } } } - } + // other bytecode bands + debug("Parsed *bc_codes (" + bcParsed + ")"); + debug("unimplemented bc_case_count"); + debug("unimplemented bc_case_value"); + debug("unimplemented bc_byte"); + debug("unimplemented bc_short"); + debug("unimplemented bc_local"); + debug("unimplemented bc_label"); + debug("unimplemented bc_intref"); + debug("unimplemented bc_floatref"); + debug("unimplemented bc_longref"); + debug("unimplemented bc_doubleref"); + int[] bcStringRef = decodeBandInt("bc_stringref", in, Codec.DELTA5, + bcStringRefCount); + debug("unimplemented bc_classref"); + int[] bcFieldRef = decodeBandInt("bc_fieldref", in, Codec.DELTA5, + bcFieldRefCount); + int[] bcMethodRef = decodeBandInt("bc_methodref", in, Codec.UNSIGNED5, + bcMethodRefCount); + int[] bcIMethodRef = decodeBandInt("bc_imethodref", in, Codec.DELTA5, + bcIMethodRefCount); + int[] bcThisField = decodeBandInt("bc_thisfield", in, Codec.UNSIGNED5, + bcThisFieldCount); + debug("unimplemented bc_superfield"); + debug("unimplemented bc_thismethod"); + debug("unimplemented bc_supermethod"); + debug("unimplemented bc_initref"); + int[] bcInitRef = decodeBandInt("bc_initref", in, Codec.UNSIGNED5, + bcInitRefCount); + debug("unimplemented bc_escref"); + debug("unimplemented bc_escrefsize"); + debug("unimplemented bc_escsize"); + debug("unimplemented bc_escbyte"); + int i = 0; + for (int c = 0; c < classCount; c++) { + int numberOfMethods = methodFlags[c].length; + for (int m = 0; m < numberOfMethods; m++) { + long methodFlag = methodFlags[c][m]; + if (!abstractModifier.matches(methodFlag) + && !nativeModifier.matches(methodFlag)) { + int maxStack = codeMaxStack[i]; + int maxLocal = codeMaxNALocals[i]; + if (!staticModifier.matches(methodFlag)) + maxLocal++; // one for 'this' parameter + maxLocal += SegmentUtils.countArgs(methodDescr[c][m]); + // TODO Move creation of code attribute until after constant + // pool resolved + CodeAttribute attr = new CodeAttribute(maxStack, maxLocal, + methodByteCodePacked[c][m]); + methodAttributes[c][m].add(attr); + i++; + } + } + } - private void parseBcBands(InputStream in) { - debug("Unimplemented bc_bands"); } private void parseClassAttrBands(InputStream in) throws IOException, @@ -740,7 +891,7 @@ debug("unimplemented class_EnclosingMethod_RC"); debug("unimplemented class_EnclosingMethod_RDN"); debug("unimplemented class_Signature_RS"); - parseMetadataBands("class"); + parseMetadataBands(AttributeLayout.CONTEXT_CLASS); debug("unimplemented class_InnerClasses_N"); debug("unimplemented class_InnerClasses_RC"); debug("unimplemented class_InnerClasses_F"); @@ -759,10 +910,8 @@ classInterfaces = new String[classCount][]; int[] classInterfaceLengths = decodeBandInt("class_interface_count", in, Codec.DELTA5, classCount); - // for (int i = 0; i < classCount; i++) { classInterfaces = parseReferences("class_interface", in, Codec.DELTA5, classCount, classInterfaceLengths, cpClass); - // } classFieldCount = decodeBandInt("class_field_count", in, Codec.DELTA5, classCount); classMethodCount = decodeBandInt("class_method_count", in, @@ -803,23 +952,55 @@ } } - private void parseCodeBands(InputStream in) throws Pack200Exception { - // look through each method - int codeBands = 0; + private void parseCodeBands(InputStream in) throws Pack200Exception, + IOException { AttributeLayout layout = attributeDefinitionMap.getAttributeLayout( AttributeLayout.ATTRIBUTE_CODE, AttributeLayout.CONTEXT_METHOD); - for (int i = 0; i < classCount; i++) { - for (int j = 0; j < methodFlags[i].length; j++) { - long flag = methodFlags[i][j]; - if (layout.matches(flag)) - codeBands++; + int codeBands = SegmentUtils.countMatches(methodFlags, layout); + int[] codeHeaders = decodeBandInt("code_headers", in, Codec.BYTE1, + codeBands); + int codeSpecialHeader = 0; + for (int i = 0; i < codeBands; i++) { + if (codeHeaders[i] == 0) + codeSpecialHeader++; + } + int[] codeMaxStackSpecials = decodeBandInt("code_max_stack", in, + Codec.UNSIGNED5, codeSpecialHeader); + int[] codeMaxNALocalsSpecials = decodeBandInt("code_max_na_locals", in, + Codec.UNSIGNED5, codeSpecialHeader); + int[] codeHandlerCountSpecials = decodeBandInt("code_handler_count", + in, Codec.UNSIGNED5, codeSpecialHeader); + + codeMaxStack = new int[codeBands]; + codeMaxNALocals = new int[codeBands]; + codeHandlerCount = new int[codeBands]; + int special = 0; + for (int i = 0; i < codeBands; i++) { + int header = 0xff & codeHeaders[i]; + if (header < 0) { + throw new IllegalStateException("Shouldn't get here"); + } else if (header == 0) { + codeMaxStack[i] = codeMaxStackSpecials[special]; + codeMaxNALocals[i] = codeMaxNALocalsSpecials[special]; + codeHandlerCount[i] = codeHandlerCountSpecials[special]; + special++; + } else if (header <= 144) { + codeMaxStack[i] = (header - 1) % 12; + codeMaxNALocals[i] = (header - 1) / 12; + codeHandlerCount[i] = 0; + } else if (header <= 208) { + codeMaxStack[i] = (header - 145) % 8; + codeMaxNALocals[i] = (header - 145) / 8; + codeHandlerCount[i] = 1; + } else if (header <= 255) { + codeMaxStack[i] = (header - 209) % 7; + codeMaxNALocals[i] = (header - 209) / 7; + codeHandlerCount[i] = 2; + } else { + throw new IllegalStateException("Shouldn't get here either"); } } - if (codeBands > 0) - throw new Error( - "Can't handle non-abstract, non-native methods/initializers at the moment (found " - + codeBands + " code bands)"); debug("unimplemented code_headers"); debug("unimplemented code_max_stack"); debug("unimplemented code_max_na_locals"); @@ -1176,7 +1357,7 @@ } } debug("unimplemented field_Signature_RS"); - parseMetadataBands("field"); + parseMetadataBands(AttributeLayout.CONTEXT_FIELD); } /** @@ -1197,15 +1378,15 @@ */ private void parseFileBands(InputStream in) throws IOException, Pack200Exception { - if (false && System.getProperty("debug.pack200") != null) { - // TODO HACK - fileSize = new long[numberOfFiles]; - fileModtime = new long[numberOfFiles]; - fileOptions = new long[numberOfFiles]; - fileName = new String[numberOfFiles]; - Arrays.fill(fileName, ""); - return; - } + // if (false && System.getProperty("debug.pack200") != null) { + // // TODO HACK + // fileSize = new long[numberOfFiles]; + // fileModtime = new long[numberOfFiles]; + // fileOptions = new long[numberOfFiles]; + // fileName = new String[numberOfFiles]; + // Arrays.fill(fileName, ""); + // return; + // } long last; fileName = parseReferences("file_name", in, Codec.UNSIGNED5, numberOfFiles, cpUTF8); @@ -1298,39 +1479,49 @@ cpUTF8); } - private void parseMetadataBands(String unit) throws Pack200Exception { + private void parseMetadataBands(int context) throws Pack200Exception { String[] RxA; - if ("method".equals(unit)) { + if (AttributeLayout.CONTEXT_METHOD == context) { RxA = new String[] { "RVA", "RIA", "RVPA", "RIPA", "AD" }; - } else if ("field".equals(unit) || "class".equals(unit)) { + } else if (AttributeLayout.CONTEXT_FIELD == context + || AttributeLayout.CONTEXT_CLASS == context) { RxA = new String[] { "RVA", "RIA" }; } else { - throw new Pack200Exception("Unknown type of metadata unit " + unit); + throw new Pack200Exception("Unknown type of metadata unit " + + context); } + // AttributeLayout layout = + // map.get(RuntimeVisibleAnnotations,class/field/method as int) + // foreachheader ... + // if layout.matches(header[n] or whatever) + String contextName = (AttributeLayout.CONTEXT_METHOD == context ? "method" + : (AttributeLayout.CONTEXT_FIELD == context ? "field" + : (AttributeLayout.CONTEXT_CLASS == context ? "class" + : "unkowon"))); for (int i = 0; i < RxA.length; i++) { String rxa = RxA[i]; if (rxa.indexOf("P") >= 0) { - debug("unimplemented " + unit + "_" + rxa + "_param_NB"); + debug("unimplemented " + contextName + "_" + rxa + "_param_NB"); } if (!rxa.equals("AD")) { - debug("unimplemented " + unit + "_" + rxa + "_anno_N"); - debug("unimplemented " + unit + "_" + rxa + "_type_RS"); - debug("unimplemented " + unit + "_" + rxa + "_pair_N"); - debug("unimplemented " + unit + "_" + rxa + "_name_RU"); + debug("unimplemented " + contextName + "_" + rxa + "_anno_N"); + debug("unimplemented " + contextName + "_" + rxa + "_type_RS"); + debug("unimplemented " + contextName + "_" + rxa + "_pair_N"); + debug("unimplemented " + contextName + "_" + rxa + "_name_RU"); } - debug("unimplemented " + unit + "_" + rxa + "_T"); - debug("unimplemented " + unit + "_" + rxa + "_caseI_KI"); - debug("unimplemented " + unit + "_" + rxa + "_caseD_KD"); - debug("unimplemented " + unit + "_" + rxa + "_caseF_KF"); - debug("unimplemented " + unit + "_" + rxa + "_caseJ_KJ"); - debug("unimplemented " + unit + "_" + rxa + "_casec_RS"); - debug("unimplemented " + unit + "_" + rxa + "_caseet_RS"); - debug("unimplemented " + unit + "_" + rxa + "_caseec_RU"); - debug("unimplemented " + unit + "_" + rxa + "_cases_RU"); - debug("unimplemented " + unit + "_" + rxa + "_casearray_N"); - debug("unimplemented " + unit + "_" + rxa + "_nesttype_RS"); - debug("unimplemented " + unit + "_" + rxa + "_nestpair_N"); - debug("unimplemented " + unit + "_" + rxa + "_nestname_RU"); + debug("unimplemented " + contextName + "_" + rxa + "_T"); + debug("unimplemented " + contextName + "_" + rxa + "_caseI_KI"); + debug("unimplemented " + contextName + "_" + rxa + "_caseD_KD"); + debug("unimplemented " + contextName + "_" + rxa + "_caseF_KF"); + debug("unimplemented " + contextName + "_" + rxa + "_caseJ_KJ"); + debug("unimplemented " + contextName + "_" + rxa + "_casec_RS"); + debug("unimplemented " + contextName + "_" + rxa + "_caseet_RS"); + debug("unimplemented " + contextName + "_" + rxa + "_caseec_RU"); + debug("unimplemented " + contextName + "_" + rxa + "_cases_RU"); + debug("unimplemented " + contextName + "_" + rxa + "_casearray_N"); + debug("unimplemented " + contextName + "_" + rxa + "_nesttype_RS"); + debug("unimplemented " + contextName + "_" + rxa + "_nestpair_N"); + debug("unimplemented " + contextName + "_" + rxa + "_nestname_RU"); } } @@ -1363,7 +1554,7 @@ } parseAttributeMethodExceptions(in); parseAttributeMethodSignature(in); - parseMetadataBands("method"); + parseMetadataBands(AttributeLayout.CONTEXT_METHOD); } /** @@ -1672,6 +1863,24 @@ } /** + * Unpacks a packed stream (either .pack. or .pack.gz) into a corresponding + * JarOuputStream. + * + * @throws Pack200Exception + * if there is a problem unpacking + * @throws IOException + * if there is a problem with I/O during unpacking + */ + public void unpack(InputStream in, JarOutputStream out) throws IOException, + Pack200Exception { + if (!in.markSupported()) + in = new BufferedInputStream(in); + // TODO Can handle multiple concatenated streams, so should deal with + // that possibility + parse(in).unpack(in, out); + } + + /** * Writes the segment to an output stream. The output stream should be * pre-buffered for efficiency. Also takes the same input stream for * reading, since the file bits may not be loaded and thus just copied from Index: src/main/java/org/apache/harmony/pack200/bytecode/ByteCode.java =================================================================== --- src/main/java/org/apache/harmony/pack200/bytecode/ByteCode.java (revision 571408) +++ src/main/java/org/apache/harmony/pack200/bytecode/ByteCode.java (working copy) @@ -289,10 +289,7 @@ protected void doWrite(DataOutputStream dos) throws IOException { // TODO operands? for (int i = 0; i < rewrite.length; i++) { - if (opcode == 231 && i == 2) - dos.writeByte(8); - else - dos.writeByte(rewrite[i]); + dos.writeByte(rewrite[i]); } } @@ -318,11 +315,7 @@ } protected ClassFileEntry[] getNestedClassFileEntries() { - if (opcode == 231) // TODO HACK - return new ClassFileEntry[] { new CPMethodRef("java/lang/Object", - ":()V") }; - else - return nested; + return nested; } public int getOpcode() { @@ -336,6 +329,11 @@ return result; } + protected void resolve(ClassConstantPool pool) { + // TODO Auto-generated method stub + super.resolve(pool); + } + public String toString() { return name; } Index: src/main/java/org/apache/harmony/pack200/bytecode/CPFieldRef.java =================================================================== --- src/main/java/org/apache/harmony/pack200/bytecode/CPFieldRef.java (revision 571408) +++ src/main/java/org/apache/harmony/pack200/bytecode/CPFieldRef.java (working copy) @@ -16,10 +16,82 @@ */ package org.apache.harmony.pack200.bytecode; -public class CPFieldRef extends CPRef { +import java.io.DataOutputStream; +import java.io.IOException; + +public class CPFieldRef extends ConstantPoolEntry { + + CPClass className; + transient int classNameIndex; + + + private CPNameAndType nameAndType; + transient int nameAndTypeIndex; public CPFieldRef(String className, String descriptor) { - super(ConstantPoolEntry.CP_Fieldref, className, descriptor); + super(ConstantPoolEntry.CP_Fieldref); + this.className = new CPClass(className); + this.nameAndType = new CPNameAndType(descriptor); + } + + + + protected ClassFileEntry[] getNestedClassFileEntries() { + ClassFileEntry[] entries = new ClassFileEntry[2]; + entries[0] = className; + entries[1] = nameAndType; + return entries; + } + + + + protected void resolve(ClassConstantPool pool) { + super.resolve(pool); + nameAndTypeIndex = pool.indexOf(nameAndType); + classNameIndex = pool.indexOf(className); + } + + protected void writeBody(DataOutputStream dos) throws IOException { + dos.writeShort(classNameIndex); + dos.writeShort(nameAndTypeIndex); + } + + + public String toString() { + return "FieldRef: " + className + "#" + nameAndType; + } + + + + public int hashCode() { + final int PRIME = 31; + int result = 1; + result = PRIME * result + ((className == null) ? 0 : className.hashCode()); + result = PRIME * result + ((nameAndType == null) ? 0 : nameAndType.hashCode()); + return result; } -} + + + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + final CPFieldRef other = (CPFieldRef) obj; + if (className == null) { + if (other.className != null) + return false; + } else if (!className.equals(other.className)) + return false; + if (nameAndType == null) { + if (other.nameAndType != null) + return false; + } else if (!nameAndType.equals(other.nameAndType)) + return false; + return true; + } + +} \ No newline at end of file Index: src/main/java/org/apache/harmony/pack200/bytecode/CodeAttribute.java =================================================================== --- src/main/java/org/apache/harmony/pack200/bytecode/CodeAttribute.java +++ src/main/java/org/apache/harmony/pack200/bytecode/CodeAttribute.java @@ -0,0 +1,100 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.harmony.pack200.bytecode; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class CodeAttribute extends Attribute { + public List attributes = new ArrayList(); + public List byteCodes = new ArrayList(); + public int codeLength; + public List exceptionTable = new ArrayList(); // of ExceptionTableEntry + // instances + public int maxLocals; + public int maxStack; + + public CodeAttribute(int maxStack, int maxLocals, byte codePacked[]) { + super("Code"); //$NON-NLS-1$ + this.maxLocals = maxLocals; + this.maxStack = maxStack; + this.codeLength = 0; + for (int i = 0; i < codePacked.length; i++) { + ByteCode byteCode = ByteCode.getByteCode(codePacked[i]); + byteCodes.add(byteCode); + this.codeLength += byteCode.getLength(); + } + } + + protected int getLength() { + int attributesSize = 0; + Iterator it = attributes.iterator(); + while (it.hasNext()) { + Attribute attribute = (Attribute) it.next(); + attributesSize += attribute.getLength(); + } + return 2 + 2 + 4 + codeLength + exceptionTable.size() * (2 + 2 + 2 + 2) + + 2 + attributesSize; + } + + protected void resolve(ClassConstantPool pool) { + super.resolve(pool); + Iterator it = attributes.iterator(); + while (it.hasNext()) { + Attribute attribute = (Attribute) it.next(); + attribute.resolve(pool); + } + it = byteCodes.iterator(); + while (it.hasNext()) { + ByteCode byteCode = (ByteCode) it.next(); + byteCode.resolve(pool); + } + } + + public String toString() { + // TODO More Info here later + return "Code: " + getLength() + " bytes"; + } + + protected void writeBody(DataOutputStream dos) throws IOException { + dos.writeShort(maxStack); + dos.writeShort(maxLocals); + dos.writeInt(codeLength); + Iterator it = byteCodes.iterator(); + while (it.hasNext()) { + ByteCode byteCode = (ByteCode) it.next(); + byteCode.write(dos); + } + dos.writeShort(exceptionTable.size()); + Iterator exceptionTableEntries = exceptionTable.iterator(); + while (exceptionTableEntries.hasNext()) { + ExceptionTableEntry entry = (ExceptionTableEntry) exceptionTableEntries + .next(); + entry.write(dos); + } + dos.writeShort(attributes.size()); + it = attributes.iterator(); + while (it.hasNext()) { + Attribute attribute = (Attribute) it.next(); + attribute.write(dos); + } + } + +} Index: src/test/java/Unpack.java =================================================================== --- src/test/java/Unpack.java +++ src/test/java/Unpack.java @@ -0,0 +1,21 @@ +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.jar.JarOutputStream; + +import org.apache.harmony.pack200.Pack200Exception; +import org.apache.harmony.pack200.Segment; + +public class Unpack { + public static void main(String[] args) throws IOException, Pack200Exception { + BufferedInputStream in = new BufferedInputStream( + args.length > 0 ? new FileInputStream(args[0]) : System.in); + JarOutputStream out = new JarOutputStream( + args.length > 1 ? (OutputStream) new FileOutputStream(args[1]) + : (OutputStream) new BufferedOutputStream(System.out)); + Segment.parse(in).writeJar(out, in); + } +}