Index: src/main/java/org/apache/harmony/pack200/AttributeLayout.java =================================================================== --- src/main/java/org/apache/harmony/pack200/AttributeLayout.java (revision 576831) +++ src/main/java/org/apache/harmony/pack200/AttributeLayout.java (working copy) @@ -248,5 +248,18 @@ public String getName() { return name; } + + public int numBackwardsCallables() { + int num = 0; + String[] split = layout.split("\\("); + if(split.length > 0) { + for (int i = 1; i < split.length; i++) { + if(split[i].startsWith("-") || split[i].startsWith("0")) { + num++; + } + } + } + return num; + } } Index: src/main/java/org/apache/harmony/pack200/AttributeLayoutMap.java =================================================================== --- src/main/java/org/apache/harmony/pack200/AttributeLayoutMap.java (revision 583385) +++ src/main/java/org/apache/harmony/pack200/AttributeLayoutMap.java (working copy) @@ -16,10 +16,6 @@ */ 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 ... import java.util.HashMap; import java.util.Iterator; import java.util.Map; @@ -224,6 +220,12 @@ return null; } + public AttributeLayout getAttributeLayout(int index, int context) + throws Pack200Exception { + Map map = layouts[context]; + return (AttributeLayout) map.get(new Integer(index)); + } + /** * The map should not contain the same layout and name combination more than * once for each context. Index: src/main/java/org/apache/harmony/pack200/BHSDCodec.java =================================================================== --- src/main/java/org/apache/harmony/pack200/BHSDCodec.java (revision 576831) +++ src/main/java/org/apache/harmony/pack200/BHSDCodec.java (working copy) @@ -15,12 +15,12 @@ * 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 ... + import java.io.EOFException; import java.io.IOException; import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; /** * TODO Comment -- quite a lot can be nicked from Codec, since this was created @@ -25,9 +25,7 @@ /** * TODO Comment -- quite a lot can be nicked from Codec, since this was created * from it - * - * @author Alex Blewitt - * + * */ public final class BHSDCodec extends Codec { @@ -155,13 +153,23 @@ x = in.read(); if (x == -1) throw new EOFException("End of stream reached whilst decoding"); - z += x * Math.pow(h, n); + z += x * Math.pow(h, n); n++; } while (n < b & isHigh(x)); - long u = z; - long twoPowS = (long)Math.pow(2, s); - double twoPowSMinusOne = twoPowS-1; + +// TODO: Decide whether to use this algorithm instead (neater, possibly quicker but less easy to understand) +// if (isSigned()) { +// int u = ((1 << s) - 1); +// if ((z & u) == u) { +// z = z >>> s ^ -1L; +// } else { +// z = z - (z >>> s); +// } +// } if(isSigned()) { + long u = z; + long twoPowS = (long)Math.pow(2, s); + double twoPowSMinusOne = twoPowS-1; if(u % twoPowS < twoPowSMinusOne) { if(cardinality < Math.pow(2, 32)) { z = (long) (u - (Math.floor(u/ twoPowS))); @@ -172,8 +180,8 @@ z = (long) (-Math.floor(u/ twoPowS) - 1); } } - if (isDelta()) - z += last; + if (isDelta()) + z += last; return z; } @@ -196,6 +204,50 @@ public boolean encodes(long value) { return (value >= smallest() && value <= largest()); } + + public byte[] encode(long value, long last) throws Pack200Exception { + if (isDelta()) { + value -= last; + } + if (!encodes(value)) { + throw new Pack200Exception("The codec " + toString() + + " does not encode the value " + value); + } + long z = value; + if (isSigned()) { + if (z < 0) { + z = (-z << s) - 1; + } else { + if (s == 1) { + z = z << s; + } else { + z += (z - z % 3) / 3; + } + } + } + List byteList = new ArrayList(); + for (int n = 0; n < b; n++) { + long byteN; + if (z < l) { + byteN = z; + } else { + byteN = z % h; + while (byteN < l) + byteN += h; + } + byteList.add(new Byte((byte) byteN)); + if (byteN < l) { + break; + } + z -= byteN; + z /= h; + } + byte[] bytes = new byte[byteList.size()]; + for (int i = 0; i < bytes.length; i++) { + bytes[i] = ((Byte) byteList.get(i)).byteValue(); + } + return bytes; + } /** * Returns true if this codec is a delta codec @@ -220,19 +272,15 @@ */ public long largest() { long result; - if (isDelta()) { - result = Long.MAX_VALUE; + // TODO This can probably be optimized into a better mathematical statement + if (s == 0) { + result = cardinality() - 1; + } else if (s == 1) { + result = cardinality() / 2 - 1; + } else if (s == 2) { + result = (3L * cardinality()) / 4 - 1; } else { - // TODO This can probably be optimized into a better mathematical statement - if (s == 0) { - result = cardinality() - 1; - } else if (s == 1) { - result = cardinality() / 2 - 1; - } else if (s == 2) { - result = (3L * cardinality()) / 4 - 1; - } else { - throw new Error("Unknown s value"); - } + throw new Error("Unknown s value"); } return Math.min((s == 0 ? ((long) Integer.MAX_VALUE) << 1 : Integer.MAX_VALUE) - 1, result); @@ -244,14 +292,10 @@ */ public long smallest() { long result; - if (isDelta()) { - result = Integer.MIN_VALUE; + if (isSigned()) { + result = -cardinality() / (1 << s); } else { - if (isSigned()) { - result = -cardinality() / (1 << s); - } else { - result = 0; - } + result = 0; } return Math.max(Integer.MIN_VALUE, result); } Index: src/main/java/org/apache/harmony/pack200/BandSet.java =================================================================== --- src/main/java/org/apache/harmony/pack200/BandSet.java (revision 583385) +++ src/main/java/org/apache/harmony/pack200/BandSet.java (working copy) @@ -16,6 +16,7 @@ */ package org.apache.harmony.pack200; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -36,7 +37,7 @@ } /** - * Decode a band and return an array of int[] values + * Decode a band and return an array of int values * * @param name * the name of the band (primarily for logging/debugging @@ -47,7 +48,7 @@ * the default codec for this band * @param count * the number of elements to read - * @return an array of decoded int[] values + * @return an array of decoded int values * @throws IOException * if there is a problem reading from the underlying input * stream @@ -60,10 +61,6 @@ Pack200Exception { // TODO Might be able to improve this directly. int[] result = new int[count]; - - // TODO We need to muck around in the scenario where the first value - // read indicates - // an uber-codec long[] longResult = decodeBandLong(name, in, defaultCodec, count); for (int i = 0; i < count; i++) { result[i] = (int) longResult[i]; @@ -70,7 +67,28 @@ } return result; } - + + /** + * Decode a band and return an array of int[] values + * + * @param name + * the name of the band (primarily for logging/debugging + * purposes) + * @param in + * the InputStream to decode from + * @param defaultCodec + * the default codec for this band + * @param counts + * the numbers of elements to read for each int array within the + * array to be returned + * @return an array of decoded int[] values + * @throws IOException + * if there is a problem reading from the underlying input + * stream + * @throws Pack200Exception + * if there is a problem decoding the value or that the value is + * invalid + */ public int[][] decodeBandInt(String name, InputStream in, BHSDCodec defaultCodec, int[] counts) throws IOException, Pack200Exception { int[][] result = new int[counts.length][]; int totalCount = 0; @@ -90,7 +108,7 @@ } /** - * Decode a band and return an array of long[] values + * Decode a band and return an array of long values * * @param name * the name of the band (primarily for logging/debugging @@ -101,7 +119,7 @@ * the default codec for this band * @param count * the number of elements to read - * @return an array of decoded long[] values + * @return an array of decoded long values * @throws IOException * if there is a problem reading from the underlying input * stream @@ -135,24 +153,39 @@ return codec.decode(count - 1, in, first); } } + + public byte[] encodeBandLong(long[] data, BHSDCodec codec) throws IOException, Pack200Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + for (int i = 0; i < data.length; i++) { + baos.write(codec.encode(data[i], i == 0 ? 0 : data[i-1])); + } + return baos.toByteArray(); + } public long[] parseFlags(String name, InputStream in, int count, - BHSDCodec codec, boolean hasHi) throws IOException, Pack200Exception { - return parseFlags(name, in, 1, new int[] { count }, (hasHi ? codec - : null), codec)[0]; + BHSDCodec codec, boolean hasHi) throws IOException, + Pack200Exception { + return parseFlags(name, in, new int[] { count }, + (hasHi ? codec : null), codec)[0]; + } + + public long[][] parseFlags(String name, InputStream in, int counts[], + BHSDCodec codec, boolean hasHi) throws IOException, + Pack200Exception { + return parseFlags(name, in, counts, (hasHi ? codec : null), codec); } - public long[][] parseFlags(String name, InputStream in, int count, - int counts[], BHSDCodec codec, boolean hasHi) throws IOException, + public long[] parseFlags(String name, InputStream in, int count, + BHSDCodec hiCodec, BHSDCodec loCodec) throws IOException, Pack200Exception { - return parseFlags(name, in, count, counts, (hasHi ? codec : null), - codec); + return parseFlags(name, in, new int[] { count }, hiCodec, loCodec)[0]; } - public long[][] parseFlags(String name, InputStream in, int count, - int counts[], BHSDCodec hiCodec, BHSDCodec loCodec) throws IOException, + public long[][] parseFlags(String name, InputStream in, int counts[], + BHSDCodec hiCodec, BHSDCodec loCodec) throws IOException, Pack200Exception { // TODO Move away from decoding into a parseBand type structure + int count = counts.length; if (count == 0) { return new long[][] { {} }; } @@ -182,7 +215,7 @@ * [0..reference.length-1]. * * @param name - * TODO + * the band name * @param in * the input stream to read from * @param codec @@ -247,12 +280,12 @@ } // TODO Merge the decode and parsing of a multiple structure into one String[] result1 = new String[sum]; - int[] decode = decodeBandInt(name, in, codec, sum); + int[] indices = decodeBandInt(name, in, codec, sum); for (int i1 = 0; i1 < sum; i1++) { - int index = decode[i1]; + int index = indices[i1]; if (index < 0 || index >= reference.length) throw new Pack200Exception( - "Something has gone wrong during parsing references"); + "Something has gone wrong during parsing references, index = " + index + ", array size = " + reference.length); result1[i1] = reference[index]; } String[] refs = result1; Index: src/main/java/org/apache/harmony/pack200/BcBands.java =================================================================== --- src/main/java/org/apache/harmony/pack200/BcBands.java (revision 583385) +++ src/main/java/org/apache/harmony/pack200/BcBands.java (working copy) @@ -21,7 +21,6 @@ import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; -import java.util.Arrays; import org.apache.harmony.pack200.bytecode.ByteCode; import org.apache.harmony.pack200.bytecode.CodeAttribute; @@ -31,8 +30,11 @@ */ public class BcBands extends BandSet { - // the bytecodes for each method in each class as they come (i.e. in their packed format) + // The bytecodes for each method in each class as they come (i.e. in their packed format) private byte[][][] methodByteCodePacked; + + // The bands + // TODO: Haven't resolved references yet. Do we want to? private int[] bcCaseCount; private int[][] bcCaseValue; private int[] bcByte; @@ -137,7 +139,6 @@ for (int i = 0; i < codes.length; i++) { codes[i] = methodByteCodePacked[c][m][i] & 0xff; } - debug(Arrays.toString(codes)); 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 @@ -467,6 +468,5 @@ public int[][] getBcEscByte() { return bcEscByte; - } - + } } Index: src/main/java/org/apache/harmony/pack200/ClassBands.java =================================================================== --- src/main/java/org/apache/harmony/pack200/ClassBands.java (revision 583385) +++ src/main/java/org/apache/harmony/pack200/ClassBands.java (working copy) @@ -20,8 +20,6 @@ import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; import org.apache.harmony.pack200.bytecode.CPClass; import org.apache.harmony.pack200.bytecode.ConstantValueAttribute; @@ -32,8 +30,6 @@ */ public class ClassBands extends BandSet { - private int classAttrCount; - private int[] classFieldCount; private long[] classFlags; @@ -45,6 +41,8 @@ private String[] classSuper; private String[] classThis; + + private ArrayList[] classAttributes; private int[] codeHandlerCount; @@ -67,7 +65,7 @@ private String[][] methodDescr; private ExceptionsAttribute[][] methodExceptions; - + private long[][] methodFlags; private AttributeLayoutMap attrMap; @@ -74,10 +72,14 @@ private CpBands cpBands; - private int codeAttrCount; + private SegmentOptions options; + + private int classCount; + private int[] methodAttrCalls; + /** - * @param header + * @param segment */ public ClassBands(Segment segment) { super(segment); @@ -84,6 +86,9 @@ this.attrMap = segment.getAttrDefinitionBands() .getAttributeDefinitionMap(); this.cpBands = segment.getCpBands(); + this.classCount = header.getClassCount(); + this.options = header.getOptions(); + } /* @@ -107,13 +112,10 @@ cpBands.getCpClass()); classSuper = parseReferences("class_super", in, Codec.DELTA5, classCount, cpBands.getCpClass()); - 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, classInterfaceLengths, cpBands.getCpClass()); - // } classFieldCount = decodeBandInt("class_field_count", in, Codec.DELTA5, classCount); classMethodCount = decodeBandInt("class_method_count", in, @@ -127,13 +129,11 @@ private void parseFieldBands(InputStream in) throws IOException, Pack200Exception { - int classCount = header.getClassCount(); - SegmentOptions options = header.getOptions(); fieldDescr = parseReferences("field_descr", in, Codec.DELTA5, classFieldCount, cpBands.getCpDescriptor()); - fieldFlags = parseFlags("field_flags", in, classCount, classFieldCount, + fieldFlags = parseFlags("field_flags", in, classFieldCount, Codec.UNSIGNED5, options.hasFieldFlagsHi()); - for (int i = 0; i < classCount; i++) { + for (int i = 0; i < fieldFlags.length; i++) { for (int j = 0; j < fieldFlags[i].length; j++) { long flag = fieldFlags[i][j]; if ((flag & (1 << 16)) != 0) @@ -140,36 +140,47 @@ fieldAttrCount++; } } - if (fieldAttrCount > 0) - throw new Error( - "There are attribute flags, and I don't know what to do with them"); - debug("unimplemented field_attr_indexes"); - debug("unimplemented field_attr_calls"); + int[] fieldAttrCounts = decodeBandInt("field_attr_count", in, Codec.UNSIGNED5, fieldAttrCount); + int[][] fieldAttrIndexes = decodeBandInt("field_attr_indexes", in, Codec.UNSIGNED5, fieldAttrCounts); + int callCount = 0; + for (int i = 0; i < fieldAttrIndexes.length; i++) { + for (int j = 0; j < fieldAttrIndexes[i].length; j++) { + int index = fieldAttrIndexes[i][j]; + AttributeLayout layout = attrMap.getAttributeLayout(index, AttributeLayout.CONTEXT_FIELD); + callCount += layout.numBackwardsCallables(); + } + } + int[] fieldAttrCalls = decodeBandInt("field_attr_calls", in, Codec.UNSIGNED5, callCount); AttributeLayout layout = attrMap.getAttributeLayout("ConstantValue", AttributeLayout.CONTEXT_FIELD); - Codec codec = layout.getCodec(); - fieldAttributes = new ArrayList[classCount][]; - for (int i = 0; i < classCount; i++) { - fieldAttributes[i] = new ArrayList[fieldFlags[i].length]; - for (int j = 0; j < fieldFlags[i].length; j++) { - fieldAttributes[i][j] = new ArrayList(); - long flag = fieldFlags[i][j]; - if (layout.matches(flag)) { - // we've got a value to read - long result = codec.decode(in); - String desc = fieldDescr[i][j]; - int colon = desc.indexOf(':'); - // String name = desc.substring(0, colon); - String type = desc.substring(colon + 1); - // TODO Got to get better at this ... in any case, it should - // be e.g. KIB or KIH - if (type.equals("B") || type.equals("H")) - type = "I"; - Object value = layout.getValue(result, type, cpBands - .getConstantPool()); - fieldAttributes[i][j] - .add(new ConstantValueAttribute(value)); - debug("Processed value " + value + " for ConstantValue"); + int constantCount = SegmentUtils.countMatches(fieldFlags, layout); + if(constantCount > 0) { + int[] field_constantValue_KQ = decodeBandInt("field_ConstantValue_KQ", in, Codec.UNSIGNED5, constantCount); + int index = 0; + fieldAttributes = new ArrayList[classCount][]; + for (int i = 0; i < classCount; i++) { + fieldAttributes[i] = new ArrayList[fieldFlags[i].length]; + for (int j = 0; j < fieldFlags[i].length; j++) { + fieldAttributes[i][j] = new ArrayList(); + long flag = fieldFlags[i][j]; + if (layout.matches(flag)) { + // we've got a value to read + long result = field_constantValue_KQ[index]; + String desc = fieldDescr[i][j]; + int colon = desc.indexOf(':'); + // String name = desc.substring(0, colon); + String type = desc.substring(colon + 1); + // TODO Got to get better at this ... in any case, it should + // be e.g. KIB or KIH + if (type.equals("B") || type.equals("H")) + type = "I"; + Object value = layout.getValue(result, type, cpBands + .getConstantPool()); + fieldAttributes[i][j] + .add(new ConstantValueAttribute(value)); + debug("Processed value " + value + " for ConstantValue"); + index++; + } } } } @@ -176,33 +187,37 @@ layout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_SIGNATURE, AttributeLayout.CONTEXT_FIELD); - codec = layout.getCodec(); -// fieldAttributes = new ArrayList[classCount][]; - for (int i = 0; i < classCount; i++) { -// fieldAttributes[i] = new ArrayList[fieldFlags[i].length]; - for (int j = 0; j < fieldFlags[i].length; j++) { -// fieldAttributes[i][j] = new ArrayList(); - long flag = fieldFlags[i][j]; - if (layout.matches(flag)) { - // we've got a value to read - long result = codec.decode(in); -// String desc = fieldDescr[i][j]; -// int colon = desc.indexOf(':'); -// // String name = desc.substring(0, colon); -// String type = desc.substring(colon + 1); -// // TODO Got to get better at this ... in any case, it should -// // be e.g. KIB or KIH -// if (type.equals("B") || type.equals("H")) -// type = "I"; -// Object value = layout.getValue(result, type, cpBands -// .getConstantPool()); -// fieldAttributes[i][j] -// .add(new ConstantValueAttribute(value)); - debug("Found a signature attribute: " + result); + int signatureCount = SegmentUtils.countMatches(fieldFlags, layout); + if (signatureCount > 0) { + int[] fieldSignatureRS = decodeBandInt("field_Signature_RS", in, Codec.UNSIGNED5, signatureCount); + int index = 0; + fieldAttributes = new ArrayList[classCount][]; + for (int i = 0; i < classCount; i++) { + fieldAttributes[i] = new ArrayList[fieldFlags[i].length]; + for (int j = 0; j < fieldFlags[i].length; j++) { + fieldAttributes[i][j] = new ArrayList(); + long flag = fieldFlags[i][j]; + if (layout.matches(flag)) { + // we've got a signature attribute + long result = fieldSignatureRS[index]; + String desc = fieldDescr[i][j]; + int colon = desc.indexOf(':'); + // String name = desc.substring(0, colon); + String type = desc.substring(colon + 1); + // TODO Got to get better at this ... in any case, it should + // be e.g. KIB or KIH + if (type.equals("B") || type.equals("H")) + type = "I"; + Object value = layout.getValue(result, type, cpBands + .getConstantPool()); + fieldAttributes[i][j] + .add(new ConstantValueAttribute(value)); + index++; + debug("Found a signature attribute: " + result); + } } } } -// debug("unimplemented field_Signature_RS"); parseFieldMetadataBands(); } @@ -208,12 +223,10 @@ private void parseMethodBands(InputStream in) throws IOException, Pack200Exception { - int classCount = header.getClassCount(); - SegmentOptions options = header.getOptions(); methodDescr = parseReferences("method_descr", in, Codec.MDELTA5, classMethodCount, cpBands.getCpDescriptor()); - methodFlags = parseFlags("method_flags", in, classCount, - classMethodCount, Codec.UNSIGNED5, options.hasMethodFlagsHi()); + methodFlags = parseFlags("method_flags", in, classMethodCount, + Codec.UNSIGNED5, options.hasMethodFlagsHi()); for (int i = 0; i < classCount; i++) { for (int j = 0; j < methodFlags[i].length; j++) { long flag = methodFlags[i][j]; @@ -220,13 +233,18 @@ if ((flag & (1 << 16)) != 0) methodAttrCount++; } + } + int[] methodAttrCounts = decodeBandInt("method_attr_count", in, Codec.UNSIGNED5, methodAttrCount); + int[][] methodAttrIndexes = decodeBandInt("method_attr_indexes", in, Codec.UNSIGNED5, methodAttrCounts); + int callCount = 0; + for (int i = 0; i < methodAttrIndexes.length; i++) { + for (int j = 0; j < methodAttrIndexes[i].length; j++) { + int index = methodAttrIndexes[i][j]; + AttributeLayout layout = attrMap.getAttributeLayout(index, AttributeLayout.CONTEXT_METHOD); + callCount += layout.numBackwardsCallables(); + } } - if (methodAttrCount > 0) - throw new Error( - "There are method attribute flags, and I don't know what to do with them"); - debug("unimplemented method_attr_count"); - debug("unimplemented method_attr_indexes"); - debug("unimplemented method_attr_calls"); + methodAttrCalls = decodeBandInt("code_attr_calls", in, Codec.UNSIGNED5, callCount); // assign empty method attributes methodAttributes = new ArrayList[classCount][]; for (int i = 0; i < classCount; i++) { @@ -236,10 +254,41 @@ } } parseAttributeMethodExceptions(in); - parseAttributeMethodSignature(in); + parseAttributeMethodSigntaure(in); parseMethodMetadataBands(); } + private void parseAttributeMethodSigntaure(InputStream in) throws IOException, Pack200Exception { + AttributeLayout layout = attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_SIGNATURE, + AttributeLayout.CONTEXT_METHOD); + int count = SegmentUtils.countMatches(methodFlags, layout); + long[] methodSignatureRS = decodeBandLong("method_signature_RS", in, Codec.UNSIGNED5, count); + int index = 0; + for (int i = 0; i < methodAttributes.length; i++) { + for (int j = 0; j < methodAttributes[i].length; j++) { + long flag = methodFlags[i][j]; + if (layout.matches(flag)) { + // we've got a signature attribute + long result = methodSignatureRS[index]; + String desc = methodDescr[i][j]; + int colon = desc.indexOf(':'); + // String name = desc.substring(0, colon); + String type = desc.substring(colon + 1); + // TODO Got to get better at this ... in any case, it should + // be e.g. KIB or KIH + if (type.equals("B") || type.equals("H")) + type = "I"; + Object value = layout.getValue(result, type, cpBands + .getConstantPool()); + methodAttributes[i][j] + .add(new ConstantValueAttribute(value)); + index++; + debug("Found a signature attribute: " + result); + } + } + } + } + /** * @param in * @throws Pack200Exception @@ -247,22 +296,13 @@ */ private void parseAttributeMethodExceptions(InputStream in) throws Pack200Exception, IOException { - // TODO Should refactor this stuff into the layout somehow - int classCount = header.getClassCount(); AttributeLayout layout = attrMap.getAttributeLayout("Exceptions", AttributeLayout.CONTEXT_METHOD); - Codec codec = layout.getCodec(); methodExceptions = new ExceptionsAttribute[classCount][]; - int[][] numExceptions = new int[classCount][]; - for (int i = 0; i < classCount; i++) { - numExceptions[i] = new int[methodFlags[i].length]; - for (int j = 0; j < methodFlags[i].length; j++) { - long flag = methodFlags[i][j]; - if (layout.matches(flag)) { - numExceptions[i][j] = (int) codec.decode(in); - } - } - } + int count = SegmentUtils.countMatches(methodFlags, layout); + int[] numExceptions = decodeBandInt("method_Exceptions_n", in, Codec.UNSIGNED5, count); + String[][] methodExceptionsRS = parseReferences("method_Exceptions_RC", in, Codec.UNSIGNED5, numExceptions, cpBands.getCpClass()); + int index = 0; for (int i = 0; i < classCount; i++) { methodExceptions[i] = new ExceptionsAttribute[methodFlags[i].length]; for (int j = 0; j < methodFlags[i].length; j++) { @@ -267,18 +307,16 @@ methodExceptions[i] = new ExceptionsAttribute[methodFlags[i].length]; for (int j = 0; j < methodFlags[i].length; j++) { long flag = methodFlags[i][j]; - int n = numExceptions[i][j]; - 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( - cpBands.getCpClass()[(int) result]); - } + if(layout.matches(flag)) { + int n = numExceptions[index]; + String[] exceptions = methodExceptionsRS[index]; + CPClass[] exceptionClasses = new CPClass[n]; + for (int k = 0; k < n; k++) { + exceptionClasses[k] = new CPClass(exceptions[k]); } - methodExceptions[i][j] = new ExceptionsAttribute(exceptions); + methodExceptions[i][j] = new ExceptionsAttribute(exceptionClasses); methodAttributes[i][j].add(methodExceptions[i][j]); + index ++; } } } @@ -284,38 +322,12 @@ } } - /** - * @param name - * @param flags - * @throws Pack200Exception - */ - private void parseAttributeUnknown(String name, int context, long[][] flags) - throws Pack200Exception { - debug("Parsing unknown attributes for " + name); - AttributeLayout layout = attrMap.getAttributeLayout(name, context); - 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)"); - } - - /** - * @param in - * - */ - private void parseAttributeMethodSignature(InputStream in) - throws Pack200Exception, IOException { - parseAttributeUnknown(AttributeLayout.ATTRIBUTE_SIGNATURE, - AttributeLayout.CONTEXT_METHOD, methodFlags); - } - private void parseClassAttrBands(InputStream in) throws IOException, Pack200Exception { - int classCount = header.getClassCount(); - SegmentOptions options = header.getOptions(); classFlags = parseFlags("class_flags", in, classCount, Codec.UNSIGNED5, options.hasClassFlagsHi()); - for (int i = 0; i < classCount; i++) { + int classAttrCount = 0; + for (int i = 0; i < classFlags.length; i++) { long flag = classFlags[i]; if ((flag & (1 << 16)) != 0) classAttrCount++; @@ -320,40 +332,113 @@ if ((flag & (1 << 16)) != 0) classAttrCount++; } - if (classAttrCount > 0) - throw new Error( - "There are attribute flags, and I don't know what to do with them"); - debug("unimplemented class_attr_count"); - debug("unimplemented class_attr_indexes"); - debug("unimplemented class_attr_calls"); - AttributeLayout layout = attrMap.getAttributeLayout( + int[] classAttrCounts = decodeBandInt("class_attr_count", in, Codec.UNSIGNED5, classAttrCount); + int[][] classAttrIndexes = decodeBandInt("class_attr_indexes", in, Codec.UNSIGNED5, classAttrCounts); + int callCount = 0; + for (int i = 0; i < classAttrIndexes.length; i++) { + for (int j = 0; j < classAttrIndexes[i].length; j++) { + int index = classAttrIndexes[i][j]; + AttributeLayout layout = attrMap.getAttributeLayout(index, AttributeLayout.CONTEXT_CLASS); + callCount += layout.numBackwardsCallables(); + } + } + int[] classAttrCalls = decodeBandInt("class_attr_calls", in, Codec.UNSIGNED5, callCount); + + AttributeLayout sourceFileLayout = attrMap.getAttributeLayout( AttributeLayout.ATTRIBUTE_SOURCE_FILE, AttributeLayout.CONTEXT_CLASS); + int sourceFileCount = SegmentUtils.countMatches(classFlags, + sourceFileLayout); + int[] classSourceFile = decodeBandInt("class_SourceFile_RUN", in, + Codec.UNSIGNED5, sourceFileCount); + + AttributeLayout enclosingMethodLayout = attrMap.getAttributeLayout( + AttributeLayout.ATTRIBUTE_ENCLOSING_METHOD, + AttributeLayout.CONTEXT_CLASS); + int enclosingMethodCount = SegmentUtils.countMatches(classFlags, + enclosingMethodLayout); + int[] enclosingMethodRC = decodeBandInt("class_EnclosingMethod_RC", in, + Codec.UNSIGNED5, enclosingMethodCount); + int[] enclosingMethodRDN = decodeBandInt("class_EnclosingMethod_RDN", in, + Codec.UNSIGNED5, enclosingMethodCount); + + AttributeLayout signatureLayout = attrMap.getAttributeLayout( + AttributeLayout.ATTRIBUTE_SIGNATURE, + AttributeLayout.CONTEXT_CLASS); + int signatureCount = SegmentUtils.countMatches(classFlags, + signatureLayout); + int[] classSignature = decodeBandInt("class_Signature_RS", in, + Codec.UNSIGNED5, signatureCount); + + parseClassMetadataBands(); + + AttributeLayout innerClassLayout = attrMap.getAttributeLayout( + AttributeLayout.ATTRIBUTE_INNER_CLASSES, + AttributeLayout.CONTEXT_CLASS); + int innerClassCount = SegmentUtils.countMatches(classFlags, + innerClassLayout); + int[] classInnerClassesN = decodeBandInt("class_InnerClasses_N", in, + Codec.UNSIGNED5, innerClassCount); + int[][] classInnerClassesRC = decodeBandInt("class_InnerClasses_RC", in, Codec.UNSIGNED5, classInnerClassesN); + int[][] classInnerClassesF = decodeBandInt("class_InnerClasses_F", in, Codec.UNSIGNED5, classInnerClassesN); + int flagsCount = 0; + for (int i = 0; i < classInnerClassesF.length; i++) { + for (int j = 0; j < classInnerClassesF[i].length; j++) { + if(classInnerClassesF[i][j] != 0) { + flagsCount++; + } + } + } + int[] classInnerClassesOuterRCN = decodeBandInt("class_InnerClasses_outer_RCN", in, Codec.UNSIGNED5, flagsCount); + int[] classInnerClassesNameRUN = decodeBandInt("class_InnerClasses_name_RUN", in, Codec.UNSIGNED5, flagsCount); + + + AttributeLayout versionLayout = attrMap.getAttributeLayout( + AttributeLayout.ATTRIBUTE_CLASS_FILE_VERSION, + AttributeLayout.CONTEXT_CLASS); + int versionCount = SegmentUtils.countMatches(classFlags, versionLayout); + int[] classFileVersionMinorH = decodeBandInt( + "class_file_version_minor_H", in, Codec.UNSIGNED5, versionCount); + int[] classFileVersionMajorH = decodeBandInt( + "class_file_version_major_H", in, Codec.UNSIGNED5, versionCount); + + + // Now process the attribute bands we have parsed + int sourceFileIndex = 0; + int enclosingMethodIndex = 0; + int signatureIndex = 0; + int innerClassIndex = 0; + int versionIndex = 0; + classAttributes = new ArrayList[classCount]; for (int i = 0; i < classCount; i++) { + classAttributes[i] = new ArrayList(); long flag = classFlags[i]; - if (layout.matches(flag)) { + if (sourceFileLayout.matches(flag)) { + long result = classSourceFile[sourceFileIndex]; // we've got a value to read // TODO File this as a sourcefile attribute and don't generate // everything below - long result = layout.getCodec().decode(in); - Object value = layout.getValue(result, cpBands + Object value = sourceFileLayout.getValue(result, cpBands .getConstantPool()); debug("Processed value " + value + " for SourceFile"); + sourceFileIndex++; + } + if(enclosingMethodLayout.matches(flag)) { + // TODO + } + if(signatureLayout.matches(flag)) { +// TODO + } + if(innerClassLayout.matches(flag)) { + // TODO + } + if(versionLayout.matches(flag)) { + // TODO } } - debug("unimplemented class_EnclosingMethod_RC"); - debug("unimplemented class_EnclosingMethod_RDN"); - debug("unimplemented class_Signature_RS"); - parseClassMetadataBands(); - debug("unimplemented class_InnerClasses_N"); - debug("unimplemented class_InnerClasses_RC"); - debug("unimplemented class_InnerClasses_F"); - debug("unimplemented class_InnerClasses_outer_RCN"); - debug("unimplemented class_InnerClasses_inner_RCN"); - debug("unimplemented class_file_version_minor_H"); - debug("unimplemented class_file_version_major_H"); } + private void parseCodeBands(InputStream in) throws Pack200Exception, IOException { AttributeLayout layout = attrMap.getAttributeLayout( @@ -359,11 +444,11 @@ AttributeLayout layout = attrMap.getAttributeLayout( AttributeLayout.ATTRIBUTE_CODE, AttributeLayout.CONTEXT_METHOD); - int codeBands = SegmentUtils.countMatches(methodFlags, layout); + int codeCount = SegmentUtils.countMatches(methodFlags, layout); int[] codeHeaders = decodeBandInt("code_headers", in, Codec.BYTE1, - codeBands); + codeCount); int codeSpecialHeader = 0; - for (int i = 0; i < codeBands; i++) { + for (int i = 0; i < codeCount; i++) { if (codeHeaders[i] == 0) codeSpecialHeader++; } @@ -374,11 +459,11 @@ int[] codeHandlerCountSpecials = decodeBandInt("code_handler_count", in, Codec.UNSIGNED5, codeSpecialHeader); - codeMaxStack = new int[codeBands]; - codeMaxNALocals = new int[codeBands]; - codeHandlerCount = new int[codeBands]; + codeMaxStack = new int[codeCount]; + codeMaxNALocals = new int[codeCount]; + codeHandlerCount = new int[codeCount]; int special = 0; - for (int i = 0; i < codeBands; i++) { + for (int i = 0; i < codeCount; i++) { int header = 0xff & codeHeaders[i]; if (header < 0) { throw new IllegalStateException("Shouldn't get here"); @@ -403,8 +488,17 @@ throw new IllegalStateException("Shouldn't get here either"); } } + int sumCodeHandlerCount = 0; + for (int i = 0; i < codeHandlerCount.length; i++) { + sumCodeHandlerCount+= codeHandlerCount[i]; + } + int[] codeHandlerStartP = decodeBandInt("code_handler_start_P", in, Codec.BCI5, sumCodeHandlerCount); + int[] codeHandlerEndPO = decodeBandInt("code_handler_end_PO", in, Codec.BRANCH5, sumCodeHandlerCount); + int[] codeHandlerCatchPO = decodeBandInt("code_handler_catch_PO", in, Codec.BRANCH5, sumCodeHandlerCount); + int[] codeHandlerClassRCN = decodeBandInt("code_handler_class_RCN", in, Codec.UNSIGNED5, sumCodeHandlerCount); + int codeFlagsCount = segment.getSegmentHeader().getOptions().hasAllCodeFlags() ? - codeBands : codeSpecialHeader; + codeCount : codeSpecialHeader; parseCodeAttrBands(in, codeFlagsCount); } @@ -410,6 +504,7 @@ private void parseCodeAttrBands(InputStream in, int codeFlagsCount) throws IOException, Pack200Exception { long[] codeFlags = parseFlags("code_flags", in, codeFlagsCount, Codec.UNSIGNED5, segment.getSegmentHeader().getOptions().hasCodeFlagsHi()); + int codeAttrCount = 0; for (int i = 0; i < codeFlagsCount; i++) { long flag = codeFlags[i]; if ((flag & (1 << 16)) != 0) @@ -415,14 +510,22 @@ if ((flag & (1 << 16)) != 0) codeAttrCount++; } - if (codeAttrCount > 0) - throw new Error( - "There are attribute flags, and I don't know what to do with them"); - debug("unimplemented code_attr_count"); - debug("unimplemented code_attr_indexes"); - debug("unimplemented code_attr_calls"); - + System.out.println("codeAttrCount = " + codeAttrCount); + int[] codeAttrCounts = decodeBandInt("code_attr_count", in, Codec.UNSIGNED5, codeAttrCount); + int[][] codeAttrIndexes = decodeBandInt("code_attr_indexes", in, Codec.UNSIGNED5, codeAttrCounts); + int callCount = 0; + for (int i = 0; i < codeAttrIndexes.length; i++) { + for (int j = 0; j < codeAttrIndexes[i].length; j++) { + int index = codeAttrIndexes[i][j]; + AttributeLayout layout = attrMap.getAttributeLayout(index, AttributeLayout.CONTEXT_CODE); + callCount += layout.numBackwardsCallables(); + } + } + System.out.println("callCount = " + callCount); + int[] codeAttrCalls = decodeBandInt("code_attr_calls", in, Codec.UNSIGNED5, callCount); + int lineNumberTableCount = SegmentUtils.countMatches(codeFlags, attrMap.getAttributeLayout(AttributeLayout.ATTRIBUTE_LINE_NUMBER_TABLE, AttributeLayout.CONTEXT_CODE)); + System.out.println("lineNumberTables = " + lineNumberTableCount); int[] lineNumberTableN = decodeBandInt("code_LineNumberTable_N", in, Codec.UNSIGNED5, lineNumberTableCount); int[][] lineNumberTableBciP = decodeBandInt("code_LineNumberTable_bci_P", in, Codec.BCI5, lineNumberTableN); int[][] lineNumberTableLine = decodeBandInt("code_LineNumberTable_line", in, Codec.UNSIGNED5, lineNumberTableN); @@ -430,6 +533,8 @@ for (int i = 0; i < types.length; i++) { String type = types[i]; int lengthNBand = SegmentUtils.countMatches(codeFlags, attrMap.getAttributeLayout(type, AttributeLayout.CONTEXT_CODE)); + System.out.println(type + " count = " + lengthNBand); + int[] nBand = decodeBandInt("code_" + type + "_N", in, Codec.UNSIGNED5, lengthNBand); int[][] bciP = decodeBandInt("code_" + type + "_bci_P", in, Codec.BCI5, nBand); int[][] spanO = decodeBandInt("code_" + type + "_span_O", in, Codec.BRANCH5, nBand); @@ -597,10 +702,6 @@ } } - public int getClassAttrCount() { - return classAttrCount; - } - public int[] getClassFieldCount() { return classFieldCount; } @@ -649,10 +750,6 @@ return fieldFlags; } - public int getMethodAttrCount() { - return methodAttrCount; - } - public ArrayList[][] getMethodAttributes() { return methodAttributes; } Index: src/main/java/org/apache/harmony/pack200/Codec.java =================================================================== --- src/main/java/org/apache/harmony/pack200/Codec.java (revision 576831) +++ src/main/java/org/apache/harmony/pack200/Codec.java (working copy) @@ -15,9 +15,7 @@ * 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 ... + import java.io.IOException; import java.io.InputStream; @@ -95,9 +93,6 @@ * by the Pack200 specification, which allow a codec to be referred to by * canonical number. TODO Add links to canonical numbers when this has been * done. - * - * @author Alex Blewitt - * @version $Revision: $ */ public abstract class Codec { /** @@ -129,7 +124,7 @@ public static final BHSDCodec DELTA5 = new BHSDCodec(5, 64, 1, 1); /** - * DELTA5 = (5,64,2,1): Used for the majority of numerical codings where + * MDELTA5 = (5,64,2,1): Used for the majority of numerical codings where * there is a correlated sequence of signed values, but where most of them * are expected to be non-negative. */ @@ -147,7 +142,7 @@ public static final BHSDCodec UDELTA5 = new BHSDCodec(5, 64, 0, 1); /** - * USIGNED5 = (5,64): Used for small unsigned values. + * UNSIGNED5 = (5,64): Used for small unsigned values. */ public static final BHSDCodec UNSIGNED5 = new BHSDCodec(5, 64); Index: src/main/java/org/apache/harmony/pack200/CodecEncoding.java =================================================================== --- src/main/java/org/apache/harmony/pack200/CodecEncoding.java (revision 565676) +++ src/main/java/org/apache/harmony/pack200/CodecEncoding.java (working copy) @@ -15,9 +15,7 @@ * 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 ... + import java.io.EOFException; import java.io.IOException; import java.io.InputStream; @@ -23,6 +21,7 @@ import java.io.InputStream; public class CodecEncoding { + /** * The canonical encodings are defined to allow a single byte to represent * one of the standard encodings. The following values are defined in the @@ -28,7 +27,7 @@ * one of the standard encodings. The following values are defined in the * Pack200 specification, and this array cannot be changed. */ - private static Codec[] canonicalCodec = { null, new BHSDCodec(1, 256), + private static final Codec[] canonicalCodec = { null, new BHSDCodec(1, 256), new BHSDCodec(1, 256, 1), new BHSDCodec(1, 256, 0, 1), new BHSDCodec(1, 256, 1, 1), new BHSDCodec(2, 256), new BHSDCodec(2, 256, 1), new BHSDCodec(2, 256, 0, 1), @@ -100,7 +99,7 @@ * @throws Pack200Exception */ public static Codec getCodec(int value, InputStream in, Codec defaultCodec) throws IOException, Pack200Exception { - // Sanity check to make sure that no-one's been buggering with + // Sanity check to make sure that no-one has changed // the canonical codecs, which would really cause havoc if (canonicalCodec.length != 116) throw new Error("Canonical encodings have been incorrectly modified"); Index: src/main/java/org/apache/harmony/pack200/CpBands.java =================================================================== --- src/main/java/org/apache/harmony/pack200/CpBands.java (revision 576831) +++ src/main/java/org/apache/harmony/pack200/CpBands.java (working copy) @@ -209,8 +209,8 @@ private void parseCpLong(InputStream in) throws IOException, Pack200Exception { int cpLongCount = header.getCpLongCount(); - cpLong = parseFlags("cp_Long", in, cpLongCount, new int[] { 1 }, - Codec.UDELTA5, Codec.DELTA5)[0]; + cpLong = parseFlags("cp_Long", in, cpLongCount, + Codec.UDELTA5, Codec.DELTA5); } /** @@ -262,7 +262,18 @@ String[] cpSignatureForm = parseReferences("cp_Signature_form", in, Codec.DELTA5, cpSignatureCount, cpUTF8); cpSignature = new String[cpSignatureCount]; - long last = 0; + int lCount = 0; + for (int i = 0; i < cpSignatureCount; i++) { + String form = cpSignatureForm[i]; + char[] chars = form.toCharArray(); + for (int j = 0; j < chars.length; j++) { + if(chars[j] == 'L') { + lCount++; + } + } + } + String[] cpSignatureClasses = parseReferences("cp_Signature_classes", in, Codec.UDELTA5, lCount, cpClass); + int index = 0; for (int i = 0; i < cpSignatureCount; i++) { String form = cpSignatureForm[i]; int len = form.length(); @@ -272,10 +283,10 @@ char c = form.charAt(j); signature.append(c); if (c == 'L') { - int index = (int) (last = Codec.UDELTA5.decode(in, last)); - String className = cpClass[index]; + String className = cpSignatureClasses[index]; list.add(className); signature.append(className); + index++; } } cpSignature[i] = signature.toString(); Index: src/main/java/org/apache/harmony/pack200/FileBands.java =================================================================== --- src/main/java/org/apache/harmony/pack200/FileBands.java (revision 572724) +++ src/main/java/org/apache/harmony/pack200/FileBands.java (working copy) @@ -67,42 +67,22 @@ Pack200Exception { int numberOfFiles = header.getNumberOfFiles(); SegmentOptions options = header.getOptions(); - 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); - fileSize = new long[numberOfFiles]; - if (options.hasFileSizeHi()) { - last = 0; - for (int i = 0; i < numberOfFiles; i++) { - fileSize[i] = (last = Codec.UNSIGNED5.decode(in, last)) << 32; - } - } - last = 0; - for (int i = 0; i < numberOfFiles; i++) { - fileSize[i] |= (last = Codec.UNSIGNED5.decode(in, last)); - } - fileModtime = new long[numberOfFiles]; + fileSize = parseFlags("file_size", in, numberOfFiles, Codec.UNSIGNED5, + options.hasFileSizeHi()); if (options.hasFileModtime()) { - last = 0; - for (int i = 0; i < numberOfFiles; i++) { - fileModtime[i] |= (last = Codec.DELTA5.decode(in, last)); - } + fileModtime = decodeBandLong("file_modtime", in, Codec.DELTA5, + numberOfFiles); + } else { + fileModtime = new long[numberOfFiles]; } - fileOptions = new long[numberOfFiles]; if (options.hasFileOptions()) { - last = 0; - for (int i = 0; i < numberOfFiles; i++) { - fileOptions[i] |= (last = Codec.UNSIGNED5.decode(in, last)); - } + fileOptions = decodeBandLong("file_options", in, Codec.UNSIGNED5, + numberOfFiles); + } else { + fileOptions = new long[numberOfFiles]; } } Index: src/main/java/org/apache/harmony/pack200/IcBands.java =================================================================== --- src/main/java/org/apache/harmony/pack200/IcBands.java (revision 572724) +++ src/main/java/org/apache/harmony/pack200/IcBands.java (working copy) @@ -62,12 +62,9 @@ int innerClassCount = header.getInnerClassCount(); icThisClass = parseReferences("ic_this_class", in, Codec.UDELTA5, innerClassCount, cpClass); - icFlags = new int[innerClassCount]; - long last = 0; + icFlags = decodeBandInt("ic_flags", in, Codec.UNSIGNED5, innerClassCount); int outerClasses = 0; - // ic_flags for (int i = 0; i < innerClassCount; i++) { - icFlags[i] = (int) (last = Codec.UNSIGNED5.decode(in, last)); if ((icFlags[i] & 1 << 16) != 0) outerClasses++; } Index: src/main/java/org/apache/harmony/pack200/Pack200Exception.java =================================================================== --- src/main/java/org/apache/harmony/pack200/Pack200Exception.java (revision 565676) +++ src/main/java/org/apache/harmony/pack200/Pack200Exception.java (working copy) @@ -15,14 +15,9 @@ * 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 ... + /** * Represents a problem with a Pack200 coding/decoding issue. - * - * @author Alex Blewitt - * @version $Revision: $ */ public class Pack200Exception extends Exception { Index: src/main/java/org/apache/harmony/pack200/PopulationCodec.java =================================================================== --- src/main/java/org/apache/harmony/pack200/PopulationCodec.java (revision 565676) +++ src/main/java/org/apache/harmony/pack200/PopulationCodec.java (working copy) @@ -15,9 +15,7 @@ * 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 ... + import java.io.IOException; import java.io.InputStream; Index: src/main/java/org/apache/harmony/pack200/RunCodec.java =================================================================== --- src/main/java/org/apache/harmony/pack200/RunCodec.java (revision 565676) +++ src/main/java/org/apache/harmony/pack200/RunCodec.java (working copy) @@ -15,9 +15,7 @@ * 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 ... + import java.io.IOException; import java.io.InputStream; @@ -26,9 +24,6 @@ * the first codec, and the remaining codes are decoded from the remaining * codec. Note that since this codec maintains state, the instances are * not reusable. - * - * @author Alex Blewitt - * @version $Revision: $ */ public class RunCodec extends Codec { private int k; Index: src/main/java/org/apache/harmony/pack200/Segment.java =================================================================== --- src/main/java/org/apache/harmony/pack200/Segment.java (revision 583385) +++ src/main/java/org/apache/harmony/pack200/Segment.java (working copy) @@ -16,10 +16,6 @@ */ 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 ... import java.io.BufferedInputStream; import java.io.DataOutputStream; import java.io.IOException; @@ -64,9 +60,6 @@ * In any case, if GZip decompression is being performed the input stream will * be buffered at a higher level, and thus this can read on a byte-oriented * basis. - * - * @author Alex Blewitt - * @version $Revision: $ */ public class Segment { Index: src/main/java/org/apache/harmony/pack200/SegmentOptions.java =================================================================== --- src/main/java/org/apache/harmony/pack200/SegmentOptions.java (revision 565676) +++ src/main/java/org/apache/harmony/pack200/SegmentOptions.java (working copy) @@ -15,9 +15,7 @@ * 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 ... + /** * Stores the combinations of bit flags that can be used in the segment header * options. Whilst this could be defined in {@link Segment}, it's cleaner to @@ -25,9 +23,6 @@ * to determine the semantic meaning of the flags. In languages with a * pre-processor, these may be defined by macros that do bitflag manipulation * instead. - * - * @author Alex Blewitt - * @version $Revision: $ */ public class SegmentOptions { private static final int DEFLATE_HINT = 1 << 5; Index: src/main/java/org/apache/harmony/pack200/bytecode/ClassConstantPool.java =================================================================== --- src/main/java/org/apache/harmony/pack200/bytecode/ClassConstantPool.java (revision 565676) +++ src/main/java/org/apache/harmony/pack200/bytecode/ClassConstantPool.java (working copy) @@ -16,10 +16,6 @@ */ package org.apache.harmony.pack200.bytecode; -// 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.ArrayList; import java.util.Iterator; import java.util.List; Index: src/main/java/org/apache/harmony/pack200/bytecode/ClassFile.java =================================================================== --- src/main/java/org/apache/harmony/pack200/bytecode/ClassFile.java (revision 565676) +++ src/main/java/org/apache/harmony/pack200/bytecode/ClassFile.java (working copy) @@ -15,9 +15,7 @@ * limitations under the License. */ package org.apache.harmony.pack200.bytecode; -//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.io.DataOutputStream; import java.io.IOException; Index: src/main/java/org/apache/harmony/pack200/bytecode/ClassFileEntry.java =================================================================== --- src/main/java/org/apache/harmony/pack200/bytecode/ClassFileEntry.java (revision 565676) +++ src/main/java/org/apache/harmony/pack200/bytecode/ClassFileEntry.java (working copy) @@ -16,10 +16,6 @@ */ package org.apache.harmony.pack200.bytecode; -// 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.io.DataOutputStream; import java.io.IOException; Index: src/main/java/org/apache/harmony/pack200/bytecode/ConstantPoolEntry.java =================================================================== --- src/main/java/org/apache/harmony/pack200/bytecode/ConstantPoolEntry.java (revision 565676) +++ src/main/java/org/apache/harmony/pack200/bytecode/ConstantPoolEntry.java (working copy) @@ -16,16 +16,10 @@ */ package org.apache.harmony.pack200.bytecode; -// 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.io.DataOutputStream; import java.io.IOException; - /** - * @author alex * */ public abstract class ConstantPoolEntry extends ClassFileEntry { Index: src/test/java/org/apache/harmony/pack200/tests/AttributeLayoutMapTest.java =================================================================== --- src/test/java/org/apache/harmony/pack200/tests/AttributeLayoutMapTest.java (revision 565676) +++ src/test/java/org/apache/harmony/pack200/tests/AttributeLayoutMapTest.java (working copy) @@ -15,9 +15,7 @@ * limitations under the License. */ package org.apache.harmony.pack200.tests; -//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 junit.framework.TestCase; import org.apache.harmony.pack200.AttributeLayout; Index: src/test/java/org/apache/harmony/pack200/tests/AttributeLayoutTest.java =================================================================== --- src/test/java/org/apache/harmony/pack200/tests/AttributeLayoutTest.java (revision 572724) +++ src/test/java/org/apache/harmony/pack200/tests/AttributeLayoutTest.java (working copy) @@ -15,9 +15,7 @@ * limitations under the License. */ package org.apache.harmony.pack200.tests; -//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 junit.framework.TestCase; import org.apache.harmony.pack200.AttributeLayout; Index: src/test/java/org/apache/harmony/pack200/tests/BandSetTest.java =================================================================== --- src/test/java/org/apache/harmony/pack200/tests/BandSetTest.java (revision 583385) +++ src/test/java/org/apache/harmony/pack200/tests/BandSetTest.java (working copy) @@ -26,12 +26,20 @@ import org.apache.harmony.pack200.BHSDCodec; import org.apache.harmony.pack200.BandSet; import org.apache.harmony.pack200.Codec; +import org.apache.harmony.pack200.CodecEncoding; import org.apache.harmony.pack200.Pack200Exception; import org.apache.harmony.pack200.Segment; +import org.apache.harmony.pack200.SegmentHeader; public class BandSetTest extends TestCase { - private BandSet bandSet = new BandSet(new Segment()) { + public class MockSegment extends Segment { + public SegmentHeader getSegmentHeader() { + return new SegmentHeader(); + } + } + + private BandSet bandSet = new BandSet(new MockSegment()) { public void pack(OutputStream outputStream) { } @@ -38,6 +46,7 @@ public void unpack(InputStream inputStream) throws IOException, Pack200Exception { } + }; public void testDecodeBandInt() throws IOException, Pack200Exception { @@ -52,11 +61,11 @@ public void testDecodeBandLong() throws IOException, Pack200Exception { BHSDCodec codec = Codec.BYTE1; - byte[] bytes = new byte[]{(byte)3,(byte)56,(byte)122,(byte)78, Byte.MAX_VALUE, Byte.MIN_VALUE}; + byte[] bytes = new byte[]{(byte)3,(byte)56,(byte)122,(byte)78, (byte)0, (byte)255}; InputStream in = new ByteArrayInputStream(bytes); - long[] longs = bandSet.decodeBandLong("Test Band", in, codec, 4); + long[] longs = bandSet.decodeBandLong("Test Band", in, codec, 6); for (int i = 0; i < longs.length; i++) { - assertEquals("Wrong value in position " + i, longs[i], bytes[i]); + assertEquals("Wrong value in position " + i, (byte)longs[i], bytes[i]); } //TODO: Should test this with other Codecs. } @@ -61,6 +70,17 @@ //TODO: Should test this with other Codecs. } + public void testDecodeBandLong2() throws IOException, Pack200Exception { + + BHSDCodec codec = Codec.DELTA5; + byte[] bytes = new byte[]{3, 1, 2, 3, 4, 5}; // 3 is decoded to -2 by DELTA5, which signifies a switch to BYTE1 + InputStream in = new ByteArrayInputStream(bytes); + long[] longs = bandSet.decodeBandLong("Test Band", in, codec, 5); + for (int i = 0; i < longs.length; i++) { + assertEquals("Wrong value in position " + i, longs[i], bytes[i + 1]); + } + } + public void testParseFlags1() { } Index: src/test/java/org/apache/harmony/pack200/tests/BcBandsTest.java =================================================================== --- src/test/java/org/apache/harmony/pack200/tests/BcBandsTest.java (revision 583385) +++ src/test/java/org/apache/harmony/pack200/tests/BcBandsTest.java (working copy) @@ -43,17 +43,7 @@ * should be replaced with properly encoded byte arrays when encoding is * implemented. */ -public class BcBandsTest extends TestCase { - - - private int numClasses = 1; - private int[] numMethods = {1}; - - public class MockSegmentHeader extends SegmentHeader { - public int getClassCount() { - return numClasses; - } - } +public class BcBandsTest extends AbstractBandsTestCase { public class MockClassBands extends ClassBands { public MockClassBands(Segment segment) { @@ -107,26 +97,7 @@ } } - public class MockAttributeDefinitionBands extends AttrDefinitionBands { - - public MockAttributeDefinitionBands(Segment segment) { - super(segment); - } - - public AttributeLayoutMap getAttributeDefinitionMap() { - try { - return new AttributeLayoutMap(); - } catch (Pack200Exception e) { - fail(e.getLocalizedMessage()); - } - return null; - } - - - - } - - public class MockSegment extends Segment { + public class MockSegment extends AbstractBandsTestCase.MockSegment { protected AttrDefinitionBands getAttrDefinitionBands() { return new MockAttributeDefinitionBands(this); } @@ -138,10 +109,6 @@ protected ClassBands getClassBands() { return new MockClassBands(this); } - - public SegmentHeader getSegmentHeader() { - return new MockSegmentHeader(); - } } BcBands bcBands = new BcBands(new MockSegment()); Index: src/test/java/org/apache/harmony/pack200/tests/CodecEncodingTest.java =================================================================== --- src/test/java/org/apache/harmony/pack200/tests/CodecEncodingTest.java (revision 565676) +++ src/test/java/org/apache/harmony/pack200/tests/CodecEncodingTest.java (working copy) @@ -15,9 +15,7 @@ * limitations under the License. */ package org.apache.harmony.pack200.tests; -//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.io.ByteArrayInputStream; import java.io.IOException; import java.util.HashMap; @@ -31,11 +29,11 @@ import org.apache.harmony.pack200.Pack200Exception; /** - * @author Alex Blewitt - * @version $Revision: $ + * */ public class CodecEncodingTest extends TestCase { - public void testCanonicalEncodings() throws IOException, Pack200Exception { + + public void testCanonicalEncodings() throws IOException, Pack200Exception { Codec defaultCodec = new BHSDCodec(2,16,0,0); assertEquals(defaultCodec,CodecEncoding.getCodec(0,null, defaultCodec)); Map map = new HashMap(); @@ -164,4 +162,5 @@ assertEquals("(5,128,2,1)",CodecEncoding.getCodec(116,new ByteArrayInputStream(new byte[] { 0x25, (byte)0x7F}), null).toString()); assertEquals("(2,128,1,1)",CodecEncoding.getCodec(116,new ByteArrayInputStream(new byte[] { 0x0B, (byte)0x7F}), null).toString()); } + } Index: src/test/java/org/apache/harmony/pack200/tests/CodecTest.java =================================================================== --- src/test/java/org/apache/harmony/pack200/tests/CodecTest.java (revision 565676) +++ src/test/java/org/apache/harmony/pack200/tests/CodecTest.java (working copy) @@ -15,9 +15,7 @@ * limitations under the License. */ package org.apache.harmony.pack200.tests; -//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.io.ByteArrayInputStream; import java.io.EOFException; import java.io.IOException; @@ -31,8 +29,7 @@ /** - * @author Alex Blewitt - * @version $Revision: $ + * */ public class CodecTest extends TestCase { Index: src/test/java/org/apache/harmony/pack200/tests/HelloWorld.java =================================================================== --- src/test/java/org/apache/harmony/pack200/tests/HelloWorld.java (revision 587092) +++ src/test/java/org/apache/harmony/pack200/tests/HelloWorld.java (working copy) @@ -15,13 +15,9 @@ * limitations under the License. */ package org.apache.harmony.pack200.tests; -//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 ... + /** * This is intended to be used as a test class for unpacking a packed Jar file. - * @author Alex Blewitt - * @version $Revision: $ */ public class HelloWorld { int i=97,j=42,k=12345; Index: src/test/java/org/apache/harmony/pack200/tests/PopulationCodecTest.java =================================================================== --- src/test/java/org/apache/harmony/pack200/tests/PopulationCodecTest.java (revision 565676) +++ src/test/java/org/apache/harmony/pack200/tests/PopulationCodecTest.java (working copy) @@ -15,9 +15,7 @@ * limitations under the License. */ package org.apache.harmony.pack200.tests; -//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.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; Index: src/test/java/org/apache/harmony/pack200/tests/SegmentOptionsTest.java =================================================================== --- src/test/java/org/apache/harmony/pack200/tests/SegmentOptionsTest.java (revision 565676) +++ src/test/java/org/apache/harmony/pack200/tests/SegmentOptionsTest.java (working copy) @@ -15,9 +15,7 @@ * limitations under the License. */ package org.apache.harmony.pack200.tests; -//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 junit.framework.TestCase; import org.apache.harmony.pack200.Pack200Exception; @@ -24,11 +22,11 @@ import org.apache.harmony.pack200.SegmentOptions; /** - * @author Alex Blewitt - * @version $Revision: $ + * */ public class SegmentOptionsTest extends TestCase { - public void testUnused() { + + public void testUnused() { int[] unused = new int[] { 3, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 }; for (int i = 0; i < unused.length; i++) { Index: src/test/java/org/apache/harmony/pack200/tests/SegmentTest.java =================================================================== --- src/test/java/org/apache/harmony/pack200/tests/SegmentTest.java (revision 583385) +++ src/test/java/org/apache/harmony/pack200/tests/SegmentTest.java (working copy) @@ -16,10 +16,15 @@ */ package org.apache.harmony.pack200.tests; -import org.apache.harmony.pack200.Segment; +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.util.jar.JarOutputStream; import junit.framework.TestCase; +import org.apache.harmony.pack200.Segment; + /** * Tests for org.apache.harmony.pack200.Segment, which is the main class for pack200. */ @@ -31,9 +36,11 @@ } public void testJustResources() throws Exception { - assertNotNull(Segment - .parse(Segment.class - .getResourceAsStream("/org/apache/harmony/pack200/tests/JustResources.pack"))); + InputStream in = Segment.class + .getResourceAsStream("/org/apache/harmony/pack200/tests/JustResources.pack"); + Segment segment = Segment.parse(in); + assertNotNull(segment); + segment.writeJar(new JarOutputStream(new FileOutputStream(File.createTempFile("just", "Resources.jar"))), in); } public void testJustResourcesGZip() throws Exception { @@ -41,7 +48,23 @@ .parse(Segment.class .getResourceAsStream("/org/apache/harmony/pack200/tests/JustResources.pack.gz"))); } - + + // Test with an archive containing Harmony's SQL module, packed with -E1 + public void testWithSqlE1() throws Exception { + assertNotNull(Segment + .parse(Segment.class + .getResourceAsStream("/org/apache/harmony/pack200/tests/sql-e1.pack.gz"))); + + } + + // Test with an archive containing Harmony's Pack200 module, packed with -E1 + public void testWithPack200E1() throws Exception { + assertNotNull(Segment + .parse(Segment.class + .getResourceAsStream("/org/apache/harmony/pack200/tests/pack200-e1.pack.gz"))); + + } + public void testInterfaceOnly() throws Exception { assertNotNull(Segment .parse(Segment.class @@ -48,4 +71,5 @@ .getResourceAsStream("/org/apache/harmony/pack200/tests/InterfaceOnly.pack"))); } + } \ No newline at end of file Index: src/test/java/org/apache/harmony/pack200/tests/AbstractBandsTestCase.java =================================================================== --- src/test/java/org/apache/harmony/pack200/tests/AbstractBandsTestCase.java +++ src/test/java/org/apache/harmony/pack200/tests/AbstractBandsTestCase.java @@ -0,0 +1,81 @@ +/* + * 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.tests; + +import junit.framework.TestCase; + +import org.apache.harmony.pack200.AttrDefinitionBands; +import org.apache.harmony.pack200.AttributeLayoutMap; +import org.apache.harmony.pack200.Pack200Exception; +import org.apache.harmony.pack200.Segment; +import org.apache.harmony.pack200.SegmentHeader; +import org.apache.harmony.pack200.SegmentOptions; + +/** + * + */ +public abstract class AbstractBandsTestCase extends TestCase { + + protected int numClasses = 1; + protected int[] numMethods = {1}; + + public class MockSegmentHeader extends SegmentHeader { + public int getClassCount() { + return numClasses; + } + + public SegmentOptions getOptions() { + try { + return new SegmentOptions(0); + } catch (Pack200Exception e) { + return null; + } + } + } + + public class MockAttributeDefinitionBands extends AttrDefinitionBands { + + public MockAttributeDefinitionBands(Segment segment) { + super(segment); + } + + public AttributeLayoutMap getAttributeDefinitionMap() { + try { + return new AttributeLayoutMap(); + } catch (Pack200Exception e) { + fail(e.getLocalizedMessage()); + } + return null; + } + + + + } + + public class MockSegment extends Segment { + + protected AttrDefinitionBands getAttrDefinitionBands() { + return new MockAttributeDefinitionBands(this); + } + + public SegmentHeader getSegmentHeader() { + return new MockSegmentHeader(); + } + } + + +} Index: src/test/java/org/apache/harmony/pack200/tests/BHSDCodecTest.java =================================================================== --- src/test/java/org/apache/harmony/pack200/tests/BHSDCodecTest.java +++ src/test/java/org/apache/harmony/pack200/tests/BHSDCodecTest.java @@ -0,0 +1,57 @@ +/* + * 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.tests; + +import java.io.ByteArrayInputStream; +import java.io.IOException; + +import junit.framework.TestCase; + +import org.apache.harmony.pack200.BHSDCodec; +import org.apache.harmony.pack200.CodecEncoding; +import org.apache.harmony.pack200.Pack200Exception; + +/** + * Tests for BHSDCodec + */ +public class BHSDCodecTest extends TestCase { + + + public void testEncodeDecode() throws IOException, Pack200Exception { + for (int i = 1; i < 116; i++) { + + BHSDCodec codec = (BHSDCodec) CodecEncoding.getCodec(i, null, null); + + // Test encode-decode with a selection of numbers within the range of the codec + long delta = (codec.largest() - codec.smallest()) / 4; + for (long j = codec.smallest(); j <= codec.largest() + 1; j += delta) { + byte[] encoded = codec.encode(j, 0); + long decoded = codec.decode(new ByteArrayInputStream(encoded), + 0); + if (j != decoded) { + fail("Failed with codec: " + codec + " expected: " + j + + ", got: " + decoded); + } + } + + // Test encode-decode with 0 + assertEquals(0, codec.decode(new ByteArrayInputStream(codec.encode( + 0, 0)), 0)); + } + } + +} \ No newline at end of file Index: src/test/java/org/apache/harmony/pack200/tests/ClassBandsTest.java =================================================================== --- src/test/java/org/apache/harmony/pack200/tests/ClassBandsTest.java +++ src/test/java/org/apache/harmony/pack200/tests/ClassBandsTest.java @@ -0,0 +1,144 @@ +/* + * 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.tests; + +import java.io.ByteArrayInputStream; +import java.io.IOException; + +import org.apache.harmony.pack200.ClassBands; +import org.apache.harmony.pack200.Codec; +import org.apache.harmony.pack200.CpBands; +import org.apache.harmony.pack200.Pack200Exception; +import org.apache.harmony.pack200.Segment; + +/** + * + */ +public class ClassBandsTest extends AbstractBandsTestCase { + + private String[] cpClasses; + private String[] cpDescriptor; + + public class MockCpBands extends CpBands { + + public MockCpBands(Segment segment) { + super(segment); + } + + public String[] getCpClass() { + return cpClasses; + } + + public String[] getCpDescriptor() { + return cpDescriptor; + } + + } + + public class MockSegment extends AbstractBandsTestCase.MockSegment { + protected CpBands getCpBands() { + return new MockCpBands(this); + } + + } + + + + ClassBands classBands = new ClassBands(new MockSegment()); + + public void testSimple() throws IOException, Pack200Exception { + cpClasses = new String[] { "Class1", "Class2", "Class3", "Interface1", "Interface2" }; + byte[] classThis = Codec.DELTA5.encode(1, 0); + byte[] classSuper = Codec.DELTA5.encode(2, 0); + byte[] classInterfaceCount = Codec.DELTA5.encode(2, 0); + byte[] classInterfaceRef1 = classBands.encodeBandLong(new long[] {3, 4}, Codec.DELTA5); + byte[] classFieldCount = Codec.DELTA5.encode(0, 0); + byte[] classMethodCount = Codec.DELTA5.encode(0, 0); + byte[] classFlags = Codec.UNSIGNED5.encode(0, 0); + byte[][] allArrays = new byte[][] { classThis, classSuper, + classInterfaceCount, classInterfaceRef1, classFieldCount, + classMethodCount, classFlags }; + int total = classThis.length + classSuper.length + + classInterfaceCount.length + classInterfaceRef1.length + + classFieldCount.length + classMethodCount.length + + classFlags.length; + byte[] bytes = new byte[total]; + int index = 0; + for (int i = 0; i < allArrays.length; i++) { + for (int j = 0; j < allArrays[i].length; j++) { + bytes[index] = allArrays[i][j]; + index++; + } + } + ByteArrayInputStream in = new ByteArrayInputStream(bytes); + classBands.unpack(in); + assertEquals(cpClasses[1], classBands.getClassThis()[0]); + assertEquals(cpClasses[2], classBands.getClassSuper()[0]); + assertEquals(1, classBands.getClassInterfaces().length); + assertEquals(2, classBands.getClassInterfaces()[0].length); + assertEquals(cpClasses[3], classBands.getClassInterfaces()[0][0]); + assertEquals(cpClasses[4], classBands.getClassInterfaces()[0][1]); + cpClasses = null; + } + + public void testWithMethods() throws Pack200Exception, IOException { + cpClasses = new String[] { "Class1", "Class2", "Class3" }; + cpDescriptor = new String[] {"method1", "method2", "method3"}; + byte[] classThis = Codec.DELTA5.encode(1, 0); + byte[] classSuper = Codec.DELTA5.encode(2, 0); + byte[] classInterfaceCount = Codec.DELTA5.encode(0, 0); + byte[] classFieldCount = Codec.DELTA5.encode(0, 0); + byte[] classMethodCount = Codec.DELTA5.encode(3, 0); + byte[] methodDescr = classBands.encodeBandLong(new long[]{0, 1, 2}, Codec.MDELTA5); + byte[] methodFlagsLo = classBands.encodeBandLong(new long[]{0, 0, 0}, Codec.UNSIGNED5); + byte[] classFlags = Codec.UNSIGNED5.encode(0, 0); + byte[][] allArrays = new byte[][] { classThis, classSuper, + classInterfaceCount, classFieldCount, classMethodCount, + methodDescr, methodFlagsLo, classFlags, }; + int total = 0; + for (int i = 0; i < allArrays.length; i++) { + total += allArrays[i].length; + } + byte[] bytes = new byte[total]; + int index = 0; + for (int i = 0; i < allArrays.length; i++) { + for (int j = 0; j < allArrays[i].length; j++) { + bytes[index] = allArrays[i][j]; + index++; + } + } + ByteArrayInputStream in = new ByteArrayInputStream(bytes); + classBands.unpack(in); + assertEquals(cpClasses[1], classBands.getClassThis()[0]); + assertEquals(cpClasses[2], classBands.getClassSuper()[0]); + assertEquals(1, classBands.getMethodDescr().length); + assertEquals(3, classBands.getMethodDescr()[0].length); + assertEquals(cpDescriptor[0], classBands.getMethodDescr()[0][0]); + assertEquals(cpDescriptor[1], classBands.getMethodDescr()[0][1]); + assertEquals(cpDescriptor[2], classBands.getMethodDescr()[0][2]); + + cpClasses = null; + cpDescriptor = null; + } + + public void testWithFields() { + + } + + + +}