Index: /Users/alex/Documents/HarmonyWorkspace/Pack200/src/test/java/org/apache/harmony/archive/tests/internal/pack200/PopulationCodecTest.java
===================================================================
--- /Users/alex/Documents/HarmonyWorkspace/Pack200/src/test/java/org/apache/harmony/archive/tests/internal/pack200/PopulationCodecTest.java (revision 440520)
+++ /Users/alex/Documents/HarmonyWorkspace/Pack200/src/test/java/org/apache/harmony/archive/tests/internal/pack200/PopulationCodecTest.java (working copy)
@@ -22,7 +22,6 @@
import junit.framework.TestCase;
-import org.apache.harmony.archive.internal.pack200.BHSDCodec;
import org.apache.harmony.archive.internal.pack200.Codec;
import org.apache.harmony.archive.internal.pack200.Pack200Exception;
import org.apache.harmony.archive.internal.pack200.PopulationCodec;
Index: /Users/alex/Documents/HarmonyWorkspace/Pack200/src/test/resources/org/apache/harmony/archive/tests/internal/pack200/HelloWorld.pack
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: /Users/alex/Documents/HarmonyWorkspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/Segment.java
===================================================================
--- /Users/alex/Documents/HarmonyWorkspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/Segment.java (revision 440520)
+++ /Users/alex/Documents/HarmonyWorkspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/Segment.java (working copy)
@@ -16,6 +16,7 @@
*/
package org.apache.harmony.archive.internal.pack200;
+import java.io.ByteArrayInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
@@ -119,18 +120,28 @@
private int attributeDefinitionCount;
- private byte[] attributeDefinitionHeader;
+ private int[] attributeDefinitionHeader;
private String[] attributeDefinitionLayout;
private String[] attributeDefinitionName;
- private byte[] bandHeadersData;
+ private InputStream bandHeadersInputStream;
private int bandHeadersSize;
private int classCount;
+ private int[] classFieldCount;
+
+ private String[][] classInterfaces;
+
+ private int[] classMethodCount;
+
+ private String[] classSuper;
+
+ private String[] classThis;
+
private String[] cpClass;
private int cpClassCount;
@@ -189,10 +200,14 @@
private int defaultClassMinorVersion;
+ private int fieldAttrCount;
+
+ private String[][] fieldDescr;
+
+ private long[][] fieldFlags;
+
private byte[][] fileBits;
- private int numberOfFiles;
-
private long[] fileModtime;
private String[] fileName;
@@ -201,39 +216,182 @@
private long[] fileSize;
+ private int[] icFlags;
+
+ private Object icName;
+
+ private String[] icOuterClass;
+
+ private String[] icThisClass;
+
private int innerClassCount;
private int major;
- private int minor;
+ private int methodAttrCount;
- private SegmentOptions options;
+ private String[][] methodDescr;
- private int segmentsRemaining;
+ private long[][] methodFlags;
- private String[] icThisClass;
+ private int minor;
- private int[] icFlags;
+ private int numberOfFiles;
- private String[] icOuterClass;
+ private SegmentOptions options;
- private Object icName;
+ private int segmentsRemaining;
- private String[] classThis;
+ private int classAttrCount;
- private String[] classSuper;
+ private long[] classFlags;
- private String[][] classInterfaces;
+ /**
+ * This is a local debugging message to aid the developer in writing this
+ * class. It will be removed before going into production. If the property
+ * 'debug.pack200' is set, this will generate messages to stderr; otherwise,
+ * it will be silent.
+ *
+ * @param message
+ * @deprecated this should be removed from production code
+ */
+ private void debug(String message) {
+ if (System.getProperty("debug.pack200") != null) {
+ System.err.println(message);
+ }
+ }
- private int[] classFieldCount;
+ /**
+ * 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 count
+ * the number of elements to read
+ * @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
+ */
+ private int[] decodeBandInt(String name, InputStream in,
+ BHSDCodec defaultCodec, int count) throws IOException,
+ Pack200Exception {
+ // TODO Might be able to improve this directly.
+ int[] result = new int[count];
- private int[] classMethodCount;
+ // 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];
+ }
+ return result;
+ }
- private String[][] fieldDescr;
+ /**
+ * Decode a band and return an array of long[] values
+ *
+ * @param name
+ * the name of the band (primarily for logging/debugging
+ * purposes)
+ * @param in
+ * the InputStream to decode from
+ * @param codec
+ * the default codec for this band
+ * @param count
+ * the number of elements to read
+ * @return an array of decoded long[] 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
+ */
+ private long[] decodeBandLong(String name, InputStream in, BHSDCodec codec,
+ int count) throws IOException, Pack200Exception {
+ long[] result = codec.decode(count, in);
+ if (result.length > 0) {
+ 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);
+ } else if (!codec.isSigned() && first >= codec.getL()
+ && 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);
+ }
+ }
+ // TODO Remove debugging code
+ debug("Parsed *" + name + " (" + result.length + ")");
+ return result;
+ }
- private long[][] fieldFlags;
+ /**
+ * Decode a scalar from the band file. A scalar is like a band, but does not
+ * perform any band code switching.
+ *
+ * @param name
+ * the name of the scalar (primarily for logging/debugging
+ * purposes)
+ * @param in
+ * the input stream to read from
+ * @param codec
+ * the codec for this scalar
+ * @return the decoded value
+ * @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
+ */
+ private long decodeScalar(String name, InputStream in, BHSDCodec codec)
+ throws IOException, Pack200Exception {
+ debug("Parsed #" + name + " (1)");
+ return codec.decode(in);
+ }
- private int fieldAttrCount;
+ /**
+ * Decode a number of scalars from the band file. A scalar is like a band,
+ * but does not perform any band code switching.
+ *
+ * @param name
+ * the name of the scalar (primarily for logging/debugging
+ * purposes)
+ * @param in
+ * the input stream to read from
+ * @param codec
+ * the codec for this scalar
+ * @return an array of decoded long[] 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
+ */
+ private long[] decodeScalar(String name, InputStream in, BHSDCodec codec,
+ int n) throws IOException, Pack200Exception {
+ // TODO Remove debugging code
+ debug("Parsed #" + name + " (" + n + ")");
+ return codec.decode(n, in);
+ }
public long getArchiveModtime() {
return archiveModtime;
@@ -243,6 +401,25 @@
return archiveSize;
}
+ /**
+ * Obtain the band headers data as an input stream. If no band headers are
+ * present, this will return an empty input stream to prevent any further
+ * reads taking place.
+ *
+ * Note that as a stream, data consumed from this input stream can't be
+ * re-used. Data is only read from this stream if the encoding is such that
+ * additional information needs to be decoded from the stream itself.
+ *
+ * @return the band headers input stream
+ */
+ public InputStream getBandHeadersInputStream() {
+ if (bandHeadersInputStream == null) {
+ bandHeadersInputStream = new ByteArrayInputStream(new byte[0]);
+ }
+ return bandHeadersInputStream;
+
+ }
+
public int getNumberOfFiles() {
return numberOfFiles;
}
@@ -258,19 +435,23 @@
private void parseArchiveFileCounts(InputStream in) throws IOException,
Pack200Exception {
if (getOptions().hasArchiveFileCounts()) {
- setArchiveSize(Codec.UNSIGNED5.decode(in) << 32
- | Codec.UNSIGNED5.decode(in));
- setSegmentsRemaining(Codec.UNSIGNED5.decode(in));
- setArchiveModtime(Codec.UNSIGNED5.decode(in));
- setNumberOfFiles(Codec.UNSIGNED5.decode(in));
+ setArchiveSize(decodeScalar("archive_size_hi", in, Codec.UNSIGNED5) << 32
+ | decodeScalar("archive_size_lo", in, Codec.UNSIGNED5));
+ setSegmentsRemaining(decodeScalar("archive_next_count", in,
+ Codec.UNSIGNED5));
+ setArchiveModtime(decodeScalar("archive_modtime", in,
+ Codec.UNSIGNED5));
+ setNumberOfFiles(decodeScalar("file_count", in, Codec.UNSIGNED5));
}
}
private void parseArchiveSpecialCounts(InputStream in) throws IOException,
Pack200Exception {
if (getOptions().hasSpecialFormats()) {
- setBandHeadersSize(Codec.UNSIGNED5.decode(in));
- setAttributeDefinitionCount(Codec.UNSIGNED5.decode(in));
+ setBandHeadersSize(decodeScalar("band_headers_size", in,
+ Codec.UNSIGNED5));
+ setAttributeDefinitionCount(decodeScalar("attr_definition_count",
+ in, Codec.UNSIGNED5));
}
}
@@ -291,102 +472,114 @@
*/
private void parseAttributeDefinition(InputStream in) throws IOException,
Pack200Exception {
- attributeDefinitionHeader = new byte[attributeDefinitionCount];
- for (int i = 0; i < attributeDefinitionCount; i++) {
- attributeDefinitionHeader[i] = (byte) Codec.BYTE1.decode(in);
- }
- attributeDefinitionName = parseReferences(in, Codec.UNSIGNED5,
- attributeDefinitionCount, cpUTF8);
- attributeDefinitionLayout = parseReferences(in, Codec.UNSIGNED5,
- attributeDefinitionCount, cpUTF8);
+ attributeDefinitionHeader = decodeBandInt("attr_definition_headers",
+ in, Codec.BYTE1, attributeDefinitionCount);
+ attributeDefinitionName = parseReferences("attr_definition_name", in,
+ Codec.UNSIGNED5, attributeDefinitionCount, cpUTF8);
+ attributeDefinitionLayout = parseReferences("attr_definition_layout",
+ in, Codec.UNSIGNED5, attributeDefinitionCount, cpUTF8);
if (attributeDefinitionCount > 0)
throw new Error("No idea what the adc is for yet");
}
private void parseBcBands(InputStream in) {
- System.err.println("Not yet implemented");
+ debug("Unimplemented bc_bands");
}
+ private void parseClassAttrBands(InputStream in) throws IOException,
+ Pack200Exception {
+ classFlags = parseFlags("class_flags", in, classCount, Codec.UNSIGNED5,
+ options.hasClassFlagsHi());
+ for (int i = 0; i < classCount; i++) {
+ long flag = classFlags[i];
+ 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");
+ debug("unimplemented class_SourceFile_RUN");
+ debug("unimplemented class_EnclosingMethod_RC");
+ debug("unimplemented class_EnclosingMethod_RDN");
+ debug("unimplemented class_Signature_RS");
+ parseMetadataBands("class");
+ 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 parseClassBands(InputStream in) throws IOException,
Pack200Exception {
- classThis = parseReferences(in, Codec.DELTA5, classCount, cpClass);
- classSuper = parseReferences(in, Codec.DELTA5, classCount, cpClass);
+ classThis = parseReferences("class_this", in, Codec.DELTA5, classCount,
+ cpClass);
+ classSuper = parseReferences("class_super", in, Codec.DELTA5,
+ classCount, cpClass);
classInterfaces = new String[classCount][];
- int[] classInterfaceLengths = new int[classCount];
- long last = 0;
+ int[] classInterfaceLengths = decodeBandInt("class_interface_count",
+ in, Codec.DELTA5, classCount);
for (int i = 0; i < classCount; i++) {
- classInterfaceLengths[i] = (int) (last = Codec.DELTA5.decode(in,
- last));
+ classInterfaces[i] = parseReferences("class_interface", in,
+ Codec.DELTA5, classInterfaceLengths[i], cpClass);
}
- for (int i = 0; i < classCount; i++) {
- classInterfaces[i] = parseReferences(in, Codec.DELTA5,
- classInterfaceLengths[i], cpClass);
- }
- classFieldCount = new int[classCount];
- last = 0;
- for (int i = 0; i < classCount; i++) {
- classFieldCount[i] = (int) (last = Codec.DELTA5.decode(in, last));
- }
- classMethodCount = new int[classCount];
- last = 0;
- for (int i = 0; i < classCount; i++) {
- classMethodCount[i] = (int) (last = Codec.DELTA5.decode(in, last));
- }
+ classFieldCount = decodeBandInt("class_field_count", in, Codec.DELTA5,
+ classCount);
+ classMethodCount = decodeBandInt("class_method_count", in,
+ Codec.DELTA5, classCount);
parseFieldBands(in);
parseMethodBands(in);
parseClassAttrBands(in);
parseCodeBands(in);
}
- private void parseCodeBands(InputStream in) {
- // TODO Auto-generated method stub
-
+ private void parseClassCounts(InputStream in) throws IOException,
+ Pack200Exception {
+ setInnerClassCount(decodeScalar("ic_count", in, Codec.UNSIGNED5));
+ setDefaultClassMinorVersion(decodeScalar("default_class_minver", in,
+ Codec.UNSIGNED5));
+ setDefaultClassMajorVersion(decodeScalar("default_class_majver", in,
+ Codec.UNSIGNED5));
+ setClassCount(decodeScalar("class_count", in, Codec.UNSIGNED5));
}
- private void parseClassAttrBands(InputStream in) {
- // TODO Auto-generated method stub
-
+ private void parseCodeBands(InputStream in) {
+ debug("unimplemented code_headers");
+ debug("unimplemented code_max_stack");
+ debug("unimplemented code_max_na_locals");
+ debug("unimplemented code_hander_count");
+ debug("unimplemented code_hander_start_P");
+ debug("unimplemented code_hander_end_PO");
+ debug("unimplemented code_hander_catch_PO");
+ debug("unimplemented code_hander_class_RC");
+ parseCodeAttrBands(in);
}
- private void parseMethodBands(InputStream in) {
- // TODO Auto-generated method stub
-
- }
-
- private void parseFieldBands(InputStream in) throws IOException,
- Pack200Exception {
- long last;
- fieldDescr = new String[classCount][];
- last = 0;
- for (int i = 0; i < classCount; i++) {
- fieldDescr[i] = parseReferences(in, Codec.DELTA5,
- classFieldCount[i], cpClass);
+ private void parseCodeAttrBands(InputStream in) {
+ debug("unimplemented code_flags");
+ debug("unimplemented code_attr_count");
+ debug("unimplemented code_attr_indexes");
+ debug("unimplemented code_attr_calls");
+ debug("unimplemented code_LineNumberTable_N");
+ debug("unimplemented code_LineNumberTable_bci_P");
+ debug("unimplemented code_LineNumberTable_line");
+ String[] types = { "LocalVariableTable", "LocalVariableTypeTable" };
+ for (int i = 0; i < types.length; i++) {
+ String type = types[i];
+ debug("unimplemented code_" + type + "_N");
+ debug("unimplemented code_" + type + "_bci_P");
+ debug("unimplemented code_" + type + "_span_O");
+ debug("unimplemented code_" + type + "_name_RU");
+ debug("unimplemented code_" + type + "_type_RS");
+ debug("unimplemented code_" + type + "_slot");
}
- fieldFlags = new long[classCount][];
- for (int i = 0; i < classCount; i++) {
- fieldFlags[i] = parseFlags(in, classFieldCount[i], Codec.UNSIGNED5,
- options.hasFieldFlagsHi());
- }
- for (int i = 0; i < classCount; i++) {
- for (int j = 0; i < fieldFlags[i].length; j++) {
- long flag = fieldFlags[i][j];
- if ((flag & (1 << 16)) != 0)
- fieldAttrCount++;
- }
- }
- if (fieldAttrCount > 0)
- throw new Error("There are attribute flags, and I don't know what to do with them");
- // TODO if we have fieldAttrcount then we ought to do other parsing
}
- private void parseClassCounts(InputStream in) throws IOException,
- Pack200Exception {
- setInnerClassCount(Codec.UNSIGNED5.decode(in));
- setDefaultClassMinorVersion(Codec.UNSIGNED5.decode(in));
- setDefaultClassMajorVersion(Codec.UNSIGNED5.decode(in));
- setClassCount(Codec.UNSIGNED5.decode(in));
- }
-
/**
* Parses the constant pool class names, using {@link #cpClassCount} to
* populate {@link #cpClass} from {@link #cpUTF8}.
@@ -401,25 +594,28 @@
*/
private void parseCpClass(InputStream in) throws IOException,
Pack200Exception {
- cpClass = parseReferences(in, Codec.UDELTA5, cpClassCount, cpUTF8);
+ cpClass = parseReferences("cp_Class", in, Codec.UDELTA5, cpClassCount,
+ cpUTF8);
}
private void parseCpCounts(InputStream in) throws IOException,
Pack200Exception {
- setCPUtf8Count(Codec.UNSIGNED5.decode(in));
+ setCPUtf8Count(decodeScalar("cp_Utf8_count", in, Codec.UNSIGNED5));
if (getOptions().hasCPNumberCounts()) {
- setCPIntCount(Codec.UNSIGNED5.decode(in));
- setCPFloatCount(Codec.UNSIGNED5.decode(in));
- setCPLongCount(Codec.UNSIGNED5.decode(in));
- setCPDoubleCount(Codec.UNSIGNED5.decode(in));
+ setCPIntCount(decodeScalar("cp_Int_count", in, Codec.UNSIGNED5));
+ setCPFloatCount(decodeScalar("cp_Float_count", in, Codec.UNSIGNED5));
+ setCPLongCount(decodeScalar("cp_Long_count", in, Codec.UNSIGNED5));
+ setCPDoubleCount(decodeScalar("cp_Double_count", in,
+ Codec.UNSIGNED5));
}
- setCPStringCount(Codec.UNSIGNED5.decode(in));
- setCPClassCount(Codec.UNSIGNED5.decode(in));
- setCPSignatureCount(Codec.UNSIGNED5.decode(in));
- setCPDescriptorCount(Codec.UNSIGNED5.decode(in));
- setCPFieldCount(Codec.UNSIGNED5.decode(in));
- setCPMethodCount(Codec.UNSIGNED5.decode(in));
- setCPIMethodCount(Codec.UNSIGNED5.decode(in));
+ setCPStringCount(decodeScalar("cp_String_count", in, Codec.UNSIGNED5));
+ setCPClassCount(decodeScalar("cp_Class_count", in, Codec.UNSIGNED5));
+ setCPSignatureCount(decodeScalar("cp_Signature_count", in,
+ Codec.UNSIGNED5));
+ setCPDescriptorCount(decodeScalar("cp_Descr_count", in, Codec.UNSIGNED5));
+ setCPFieldCount(decodeScalar("cp_Field_count", in, Codec.UNSIGNED5));
+ setCPMethodCount(decodeScalar("cp_Method_count", in, Codec.UNSIGNED5));
+ setCPIMethodCount(decodeScalar("cp_Imethod_count", in, Codec.UNSIGNED5));
}
/**
@@ -440,10 +636,10 @@
*/
private void parseCpDescriptor(InputStream in) throws IOException,
Pack200Exception {
- String[] cpDescriptorNames = parseReferences(in, Codec.DELTA5,
- cpDescriptorCount, cpUTF8);
- String[] cpDescriptorTypes = parseReferences(in, Codec.UDELTA5,
- cpDescriptorCount, cpSignature);
+ String[] cpDescriptorNames = parseReferences("cp_Descr_name", in,
+ Codec.DELTA5, cpDescriptorCount, cpUTF8);
+ String[] cpDescriptorTypes = parseReferences("cp_Descr_type", in,
+ Codec.UDELTA5, cpDescriptorCount, cpSignature);
cpDescriptor = new String[cpDescriptorCount];
for (int i = 0; i < cpDescriptorCount; i++) {
cpDescriptor[i] = cpDescriptorNames[i] + ":" + cpDescriptorTypes[i];
@@ -453,17 +649,13 @@
private void parseCpDouble(InputStream in) throws IOException,
Pack200Exception {
cpDouble = new double[cpDoubleCount];
- long[] lastBits = new long[cpDoubleCount];
- long last = 0;
+ long[] hiBits = decodeBandLong("cp_Double_hi", in, Codec.UDELTA5,
+ cpDoubleCount);
+ long[] loBits = decodeBandLong("cp_Double_lo", in, Codec.DELTA5,
+ cpDoubleCount);
for (int i = 0; i < cpDoubleCount; i++) {
- last = Codec.UDELTA5.decode(in, last);
- lastBits[i] = last << 32;
+ cpDouble[i] = Double.longBitsToDouble(hiBits[i] << 32 | loBits[i]);
}
- for (int i = 0; i < cpDoubleCount; i++) {
- last = Codec.DELTA5.decode(in, last);
- lastBits[i] = lastBits[i] | last;
- cpDouble[i] = Double.longBitsToDouble(lastBits[i]);
- }
}
/**
@@ -480,18 +672,19 @@
*/
private void parseCpField(InputStream in) throws IOException,
Pack200Exception {
- cpFieldClass = parseReferences(in, Codec.DELTA5, cpFieldCount, cpClass);
- cpFieldDescriptor = parseReferences(in, Codec.UDELTA5, cpFieldCount,
- cpDescriptor);
+ cpFieldClass = parseReferences("cp_Field_class", in, Codec.DELTA5,
+ cpFieldCount, cpClass);
+ cpFieldDescriptor = parseReferences("cp_Field_desc", in, Codec.UDELTA5,
+ cpFieldCount, cpDescriptor);
}
private void parseCpFloat(InputStream in) throws IOException,
Pack200Exception {
cpFloat = new float[cpFloatCount];
- long last = 0;
+ int floatBits[] = decodeBandInt("cp_Float", in, Codec.UDELTA5,
+ cpFloatCount);
for (int i = 0; i < cpFloatCount; i++) {
- last = Codec.UDELTA5.decode(in, last);
- cpFloat[i] = Float.intBitsToFloat((int) last);
+ cpFloat[i] = Float.intBitsToFloat(floatBits[i]);
}
}
@@ -510,10 +703,10 @@
*/
private void parseCpIMethod(InputStream in) throws IOException,
Pack200Exception {
- cpIMethodClass = parseReferences(in, Codec.DELTA5, cpIMethodCount,
- cpClass);
- cpIMethodDescriptor = parseReferences(in, Codec.UDELTA5,
- cpIMethodCount, cpDescriptor);
+ cpIMethodClass = parseReferences("cp_Imethod_class", in, Codec.DELTA5,
+ cpIMethodCount, cpClass);
+ cpIMethodDescriptor = parseReferences("cp_Imethod_desc", in,
+ Codec.UDELTA5, cpIMethodCount, cpDescriptor);
}
private void parseCpInt(InputStream in) throws IOException,
@@ -528,34 +721,10 @@
private void parseCpLong(InputStream in) throws IOException,
Pack200Exception {
- cpLong = parseFlags(in, cpLongCount, Codec.UDELTA5, Codec.DELTA5);
+ cpLong = parseFlags("cp_Long", in, cpLongCount, Codec.UDELTA5,
+ Codec.DELTA5);
}
- private long[] parseFlags(InputStream in, int count, Codec codec,
- boolean hasHi) throws IOException, Pack200Exception {
- return parseFlags(in, count, (hasHi ? codec : null), codec);
- }
-
- private long[] parseFlags(InputStream in, int count, Codec codec)
- throws IOException, Pack200Exception {
- return parseFlags(in, count, codec, true);
- }
-
- private long[] parseFlags(InputStream in, int count, Codec hiCodec,
- Codec loCodec) throws IOException, Pack200Exception {
- long[] result = new long[count];
- long last = 0;
- for (int i = 0; i < count && hiCodec != null; i++) {
- last = hiCodec.decode(in, last);
- result[i] = last << 32;
- }
- for (int i = 0; i < count; i++) {
- last = loCodec.decode(in, last);
- result[i] = result[i] | last;
- }
- return result;
- }
-
/**
* Parses the constant pool method definitions, using {@link #cpMethodCount}
* to populate {@link #cpMethodClass} and {@link #cpMethodDescriptor}.
@@ -570,10 +739,10 @@
*/
private void parseCpMethod(InputStream in) throws IOException,
Pack200Exception {
- cpMethodClass = parseReferences(in, Codec.DELTA5, cpMethodCount,
- cpClass);
- cpMethodDescriptor = parseReferences(in, Codec.UDELTA5, cpMethodCount,
- cpDescriptor);
+ cpMethodClass = parseReferences("cp_Method_class", in, Codec.DELTA5,
+ cpMethodCount, cpClass);
+ cpMethodDescriptor = parseReferences("cp_Method_desc", in,
+ Codec.UDELTA5, cpMethodCount, cpDescriptor);
}
/**
@@ -600,8 +769,8 @@
*/
private void parseCpSignature(InputStream in) throws IOException,
Pack200Exception {
- String[] cpSignatureForm = parseReferences(in, Codec.DELTA5,
- cpSignatureCount, cpUTF8);
+ String[] cpSignatureForm = parseReferences("cp_Signature_form", in,
+ Codec.DELTA5, cpSignatureCount, cpUTF8);
cpSignature = new String[cpSignatureCount];
long last = 0;
for (int i = 0; i < cpSignatureCount; i++) {
@@ -647,6 +816,7 @@
private void parseCpUtf8(InputStream in) throws IOException,
Pack200Exception {
+ // TODO Update codec.decode -> decodeScalar
cpUTF8 = new String[(int) cpUTF8Count];
cpUTF8[0] = "";
int[] prefix = new int[cpUTF8Count];
@@ -709,6 +879,35 @@
}
}
+ private void parseFieldBands(InputStream in) throws IOException,
+ Pack200Exception {
+ fieldDescr = new String[classCount][];
+ for (int i = 0; i < classCount; i++) {
+ fieldDescr[i] = parseReferences("field_descr", in, Codec.DELTA5,
+ classFieldCount[i], cpDescriptor);
+ }
+ fieldFlags = new long[classCount][];
+ for (int i = 0; i < classCount; i++) {
+ fieldFlags[i] = parseFlags("field_flags", in, classFieldCount[i],
+ Codec.UNSIGNED5, options.hasFieldFlagsHi());
+ }
+ for (int i = 0; i < classCount; i++) {
+ for (int j = 0; j < fieldFlags[i].length; j++) {
+ long flag = fieldFlags[i][j];
+ if ((flag & (1 << 16)) != 0)
+ 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");
+ debug("unimplemented field_ConstantValueKQ");
+ debug("unimplemented field_Signature_RS");
+ parseMetadataBands("field");
+ }
+
/**
* Parses the file band headers (not including the actual bits themselves).
* At the end of this parse call, the input stream will be positioned at the
@@ -728,7 +927,8 @@
private void parseFileBands(InputStream in) throws IOException,
Pack200Exception {
long last;
- fileName = parseReferences(in, Codec.UNSIGNED5, numberOfFiles, cpUTF8);
+ fileName = parseReferences("file_name", in, Codec.UNSIGNED5,
+ numberOfFiles, cpUTF8);
fileSize = new long[numberOfFiles];
if (options.hasFileSizeHi()) {
last = 0;
@@ -756,22 +956,121 @@
}
}
+ private long[] parseFlags(String name, InputStream in, int count,
+ Codec codec) throws IOException, Pack200Exception {
+ return parseFlags(name, in, count, codec, true);
+ }
+
+ private long[] parseFlags(String name, InputStream in, int count,
+ Codec codec, boolean hasHi) throws IOException, Pack200Exception {
+ return parseFlags(name, in, count, (hasHi ? codec : null), codec);
+ }
+
+ private long[] parseFlags(String name, InputStream in, int count,
+ Codec hiCodec, Codec loCodec) throws IOException, Pack200Exception {
+ long[] result = new long[count];
+ // TODO Refactor into band parsing
+ long last = 0;
+ for (int i = 0; i < count && hiCodec != null; i++) {
+ last = hiCodec.decode(in, last);
+ result[i] = last << 32;
+ }
+ for (int i = 0; i < count; i++) {
+ last = loCodec.decode(in, last);
+ result[i] = result[i] | last;
+ }
+ // TODO Remove debugging code
+ debug("Parsed *" + name + " (" + result.length + ")");
+ return result;
+ }
+
private void parseIcBands(InputStream in) throws IOException,
Pack200Exception {
- icThisClass = parseReferences(in, Codec.UDELTA5, innerClassCount,
- cpClass);
+ icThisClass = parseReferences("ic_this_class", in, Codec.UDELTA5,
+ innerClassCount, cpClass);
icFlags = new int[innerClassCount];
long last = 0;
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++;
}
- icOuterClass = parseReferences(in, Codec.DELTA5, outerClasses, cpClass);
- icName = parseReferences(in, Codec.DELTA5, outerClasses, cpUTF8);
+ icOuterClass = parseReferences("ic_outer_class", in, Codec.DELTA5,
+ outerClasses, cpClass);
+ icName = parseReferences("ic_name", in, Codec.DELTA5, outerClasses,
+ cpUTF8);
}
+ private void parseMethodBands(InputStream in) throws IOException,
+ Pack200Exception {
+ methodDescr = new String[classCount][];
+ for (int i = 0; i < classCount; i++) {
+ methodDescr[i] = parseReferences("method_descr", in, Codec.MDELTA5,
+ classMethodCount[i], cpDescriptor);
+ }
+ methodFlags = new long[classCount][];
+ for (int i = 0; i < classCount; i++) {
+ methodFlags[i] = parseFlags("method_flags", in,
+ classMethodCount[i], 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];
+ if ((flag & (1 << 16)) != 0)
+ methodAttrCount++;
+ }
+ }
+ 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");
+ debug("unimplemented method_Exceptions_N");
+ debug("unimplemented method_Exceptions_RC");
+ debug("unimplemented method_Signature_RS");
+ parseMetadataBands("method");
+ }
+
+ private void parseMetadataBands(String unit) throws Pack200Exception {
+ String[] RxA;
+ if ("method".equals(unit)) {
+ RxA = new String[] { "RVA", "RIA", "RVPA", "RIPA", "AD" };
+ } else if ("field".equals(unit) || "class".equals(unit)) {
+ RxA = new String[] { "RVA", "RIA" };
+ } else {
+ throw new Pack200Exception("Unknown type of metadata unit " + unit);
+ }
+ for (int i = 0; i < RxA.length; i++) {
+ String rxa = RxA[i];
+ if (rxa.indexOf("P") >= 0) {
+ debug("unimplemented " + unit + "_" + 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 " + 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");
+ }
+ }
+
/**
* Helper method to parse count references from in,
* using codec to decode the values as indexes into
@@ -779,6 +1078,8 @@
* exception is thrown if a decoded index falls outside the range
* [0..reference.length-1].
*
+ * @param name
+ * TODO
* @param in
* the input stream to read from
* @param codec
@@ -788,19 +1089,21 @@
* @param reference
* the array of values to use for the indexes; often
* {@link #cpUTF8}
+ *
* @throws IOException
* if a problem occurs during reading from the underlying stream
* @throws Pack200Exception
* if a problem occurs with an unexpected value or unsupported
* codec
*/
- private String[] parseReferences(InputStream in, Codec codec, int count,
- String[] reference) throws IOException, Pack200Exception {
+ private String[] parseReferences(String name, InputStream in,
+ BHSDCodec codec, int count, String[] reference) throws IOException,
+ Pack200Exception {
String[] result = new String[count];
- long last = 0;
+ int[] decode = decodeBandInt(name, in, codec, count);
for (int i = 0; i < count; i++) {
- int index = (int) (last = codec.decode(in, last));
- if (index < 0 || index > reference.length)
+ int index = decode[i];
+ if (index < 0 || index >= reference.length)
throw new Pack200Exception(
"Something has gone wrong during parsing references");
result[i] = reference[index];
@@ -822,6 +1125,7 @@
*/
private void parseSegment(InputStream in) throws IOException,
Pack200Exception {
+ debug("-------");
parseSegmentHeader(in);
if (bandHeadersSize > 0) {
byte[] bandHeaders = new byte[(int) bandHeadersSize];
@@ -842,8 +1146,8 @@
parseCpIMethod(in);
parseAttributeDefinition(in);
parseIcBands(in);
- parseClassBands(in); // Not yet implemented
- parseBcBands(in); // Not yet implemented
+ parseClassBands(in);
+ parseBcBands(in);
// TODO Re-enable these after completing class/bytecode bands
// parseFileBands(in);
// processFileBits(in); // this just caches them in file_bits; it should
@@ -852,12 +1156,17 @@
private void parseSegmentHeader(InputStream in) throws IOException,
Pack200Exception, Error, Pack200Exception {
+ long word[] = decodeScalar("archive_magic_word", in, Codec.BYTE1,
+ magic.length);
for (int m = 0; m < magic.length; m++)
- if (in.read() != magic[m])
+ if (word[m] != magic[m])
throw new Error("Bad header");
- setMinorVersion((int) Codec.UNSIGNED5.decode(in));
- setMajorVersion((int) Codec.UNSIGNED5.decode(in));
- setOptions(new SegmentOptions((int) Codec.UNSIGNED5.decode(in, 0)));
+ setMinorVersion((int) decodeScalar("archive_minver", in,
+ Codec.UNSIGNED5));
+ setMajorVersion((int) decodeScalar("archive_majver", in,
+ Codec.UNSIGNED5));
+ setOptions(new SegmentOptions((int) decodeScalar("archive_options", in,
+ Codec.UNSIGNED5)));
parseArchiveFileCounts(in);
parseArchiveSpecialCounts(in);
parseCpCounts(in);
@@ -893,7 +1202,7 @@
}
private void setBandHeadersData(byte[] bandHeaders) {
- this.bandHeadersData = bandHeaders;
+ this.bandHeadersInputStream = new ByteArrayInputStream(bandHeaders);
}
private void setBandHeadersSize(long value) {
Index: /Users/alex/Documents/HarmonyWorkspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/PopulationCodec.java
===================================================================
--- /Users/alex/Documents/HarmonyWorkspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/PopulationCodec.java (revision 440520)
+++ /Users/alex/Documents/HarmonyWorkspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/PopulationCodec.java (working copy)
@@ -19,7 +19,6 @@
import java.io.IOException;
import java.io.InputStream;
-import java.util.ArrayList;
public class PopulationCodec extends Codec {
private Codec favouredCodec;
Index: /Users/alex/Documents/HarmonyWorkspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/Codec.java
===================================================================
--- /Users/alex/Documents/HarmonyWorkspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/Codec.java (revision 440520)
+++ /Users/alex/Documents/HarmonyWorkspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/Codec.java (working copy)
@@ -101,53 +101,53 @@
/**
* BCI5 = (5,4): Used for storing branching information in bytecode.
*/
- public static Codec BCI5 = new BHSDCodec(5, 4);
+ public static final BHSDCodec BCI5 = new BHSDCodec(5, 4);
/**
* BRANCH5 = (5,4,2): Used for storing branching information in bytecode.
*/
- public static final Codec BRANCH5 = new BHSDCodec(5, 4, 2);
+ public static final BHSDCodec BRANCH5 = new BHSDCodec(5, 4, 2);
/**
* BYTE1 = (1,256): Used for storing plain bytes.
*/
- public static final Codec BYTE1 = new BHSDCodec(1, 256);
+ public static final BHSDCodec BYTE1 = new BHSDCodec(1, 256);
/**
* CHAR3 = (3,128): Used for storing text (UTF-8) strings. NB This isn't
* quite the same as UTF-8, but has similar properties; ASCII characters
* < 127 are stored in a single byte.
*/
- public static final Codec CHAR3 = new BHSDCodec(3, 128);
+ public static final BHSDCodec CHAR3 = new BHSDCodec(3, 128);
/**
* DELTA5 = (5,64,1,1): Used for the majority of numerical codings where
* there is a correlated sequence of signed values.
*/
- public static final Codec DELTA5 = new BHSDCodec(5, 64, 1, 1);
+ public static final BHSDCodec DELTA5 = new BHSDCodec(5, 64, 1, 1);
/**
* DELTA5 = (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.
*/
- public static final Codec MDELTA5 = new BHSDCodec(5, 64, 2, 1);
+ public static final BHSDCodec MDELTA5 = new BHSDCodec(5, 64, 2, 1);
/**
* SIGNED5 = (5,64,1): Used for small signed values.
*/
- public static final Codec SIGNED5 = new BHSDCodec(5, 64, 1);
+ public static final BHSDCodec SIGNED5 = new BHSDCodec(5, 64, 1);
/**
* UDELTA5 = (5,64,0,1): Used for the majority of numerical codings where
* there is a correlated sequence of unsigned values.
*/
- public static final Codec UDELTA5 = new BHSDCodec(5, 64, 0, 1);
+ public static final BHSDCodec UDELTA5 = new BHSDCodec(5, 64, 0, 1);
/**
* USIGNED5 = (5,64): Used for small unsigned values.
*/
- public static final Codec UNSIGNED5 = new BHSDCodec(5, 64);
+ public static final BHSDCodec UNSIGNED5 = new BHSDCodec(5, 64);
/**
* Decode a sequence of bytes from the given input stream, returning the
Index: /Users/alex/Documents/HarmonyWorkspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/BHSDCodec.java
===================================================================
--- /Users/alex/Documents/HarmonyWorkspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/BHSDCodec.java (revision 440520)
+++ /Users/alex/Documents/HarmonyWorkspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/BHSDCodec.java (working copy)
@@ -27,7 +27,7 @@
* @author Alex Blewitt
*
*/
-public class BHSDCodec extends Codec {
+public final class BHSDCodec extends Codec {
/**
* The maximum number of bytes in each coding word
@@ -156,7 +156,7 @@
// When s=0, {1,2,3,4} is mapped to {1,2,3,4}
// When s=1, {1,2,3,4} is mapped to {-1,1,-2,2...}
// When s=2, {1,2,3,4} is mapped to {1,2,3,-1...}
- if (s > 0) {
+ if (isSigned()) {
int u = ((1 << s) - 1);
if ((z & u) == u) {
z = z >>> s ^ -1L;
@@ -164,7 +164,7 @@
z = z - (z >>> s);
}
}
- if (d == 1)
+ if (isDelta())
z += last;
return z;
}
@@ -181,13 +181,32 @@
}
/**
+ * Returns true if this codec is a delta codec
+ * @return true if this codec is a delta codec
+ */
+ public boolean isDelta() {
+ return d != 0;
+ }
+
+ /**
+ * Returns true if this codec is a signed codec
+ * @return true if this codec is a signed codec
+ */
+ public boolean isSigned() {
+ return s != 0;
+ }
+
+ /**
* Returns the largest value that this codec can represent.
*
* @eturn the largest value that this codec can represent.
*/
public long largest() {
long result;
- if (d == 0) {
+ if (isDelta()) {
+ result = Long.MAX_VALUE;
+ } else {
+ // TODO This can probably be optimised into a better mathematical statement
if (s == 0) {
result = cardinality() - 1;
} else if (s == 1) {
@@ -197,13 +216,10 @@
} else {
throw new Error("Unknown s value");
}
- } else {
- result = Long.MAX_VALUE;
}
return Math.min((s == 0 ? ((long) Integer.MAX_VALUE) << 1
: Integer.MAX_VALUE) - 1, result);
}
-
/**
* Returns the smallest value that this codec can represent.
*
@@ -211,18 +227,17 @@
*/
public long smallest() {
long result;
- if (d == 0) {
- if (s == 0) {
+ if (isDelta()) {
+ result = Integer.MIN_VALUE;
+ } else {
+ if (isSigned()) {
+ result = -cardinality() / (1 << s);
+ } else {
result = 0;
- } else {
- result = -cardinality() / (1 << s);
}
- } else {
- result = Integer.MIN_VALUE;
}
return Math.max(Integer.MIN_VALUE, result);
}
-
/**
* Returns the codec in the form (1,256) or (1,64,1,1). Note that trailing
* zero fields are not shown.
@@ -245,4 +260,24 @@
return buffer.toString();
}
+ /**
+ * @return the b
+ */
+ public int getB() {
+ return b;
+ }
+
+ /**
+ * @return the h
+ */
+ public int getH() {
+ return h;
+ }
+
+ /**
+ * @return the l
+ */
+ public int getL() {
+ return l;
+ }
}