Index: src/main/java/org/apache/harmony/pack200/AttributeLayout.java
===================================================================
--- src/main/java/org/apache/harmony/pack200/AttributeLayout.java (revision 572384)
+++ src/main/java/org/apache/harmony/pack200/AttributeLayout.java (working copy)
@@ -20,7 +20,6 @@
// 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 org.apache.harmony.pack200.Segment.SegmentConstantPool;
public class AttributeLayout implements IMatcher {
static class Key {
@@ -111,9 +110,8 @@
private static final String[] contextNames = { "Class", "Field", "Method", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
"Code", }; //$NON-NLS-1$
- private static Object getValue(String layout, long value, Segment segment)
+ private static Object getValue(String layout, long value, SegmentConstantPool pool)
throws Pack200Exception {
- SegmentConstantPool pool = segment.getConstantPool();
if (layout.startsWith("R")) { //$NON-NLS-1$
// references
if (layout.indexOf('N') != -1)
@@ -210,11 +208,11 @@
return layout;
}
- public Object getValue(long value, Segment segment) throws Pack200Exception {
- return getValue(layout, value, segment);
+ public Object getValue(long value, SegmentConstantPool pool) throws Pack200Exception {
+ return getValue(layout, value, pool);
}
- public Object getValue(long value, String type, Segment segment)
+ public Object getValue(long value, String type, SegmentConstantPool pool)
throws Pack200Exception {
// TODO This really needs to be better tested, esp. the different types
// TODO This should have the ability to deal with RUN stuff too, and
@@ -221,14 +219,14 @@
// unions
if (layout.startsWith("KQ")) { //$NON-NLS-1$
if (type.equals("Ljava/lang/String;")) { //$NON-NLS-1$
- Object value2 = getValue("KS", value, segment); //$NON-NLS-1$
+ Object value2 = getValue("KS", value, pool); //$NON-NLS-1$
return value2;
} else {
return getValue("K" + type + layout.substring(2), value, //$NON-NLS-1$
- segment);
+ pool);
}
} else {
- return getValue(layout, value, segment);
+ return getValue(layout, value, pool);
}
}
Index: src/main/java/org/apache/harmony/pack200/Codec.java
===================================================================
--- src/main/java/org/apache/harmony/pack200/Codec.java (revision 565676)
+++ src/main/java/org/apache/harmony/pack200/Codec.java (working copy)
@@ -227,4 +227,32 @@
}
return result;
}
+
+ /**
+ * Decodes a sequence of n values from in.
+ *
+ * @param n
+ * the number of values to decode
+ * @param in
+ * the input stream to read from
+ * @param firstValue
+ * the first value in the band if it has already been read
+ * @return an array of long values corresponding to values
+ * decoded, with firstValue as the first value in the array.
+ * @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 long[] decode(int n, InputStream in, long firstValue) throws IOException,
+ Pack200Exception {
+ long result[] = new long[n + 1];
+ long last = 0;
+ for(int i=1;iint[] values
+ * This performs the actual work of parsing against a non-static instance of
+ * Segment.
*
- * @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
+ * the input stream to read from
* @throws IOException
- * if there is a problem reading from the underlying input
- * stream
+ * if a problem occurs during reading from the underlying stream
* @throws Pack200Exception
- * if there is a problem decoding the value or that the value is
- * invalid
+ * if a problem occurs with an unexpected value or unsupported
+ * codec
*/
- private int[] decodeBandInt(String name, InputStream in,
- BHSDCodec defaultCodec, int count) throws IOException,
+ private void parseSegment(InputStream in) throws IOException,
Pack200Exception {
- // TODO Might be able to improve this directly.
- int[] result = new int[count];
+ debug("-------");
+ header = new SegmentHeader();
+ header.unpack(in);
+ cpBands = new CpBands(this);
+ cpBands.unpack(in);
+ attrDefinitionBands = new AttrDefinitionBands(this);
+ attrDefinitionBands.unpack(in);
+ icBands = new IcBands(this);
+ icBands.unpack(in);
+ classBands = new ClassBands(this);
+ classBands.unpack(in);
+ bcBands = new BcBands(this);
+ bcBands.unpack(in);
+ fileBands = new FileBands(this);
+ fileBands.unpack(in);
+ }
+
+ /**
+ * Unpacks a packed stream (either .pack. or .pack.gz) into a corresponding
+ * JarOuputStream.
+ *
+ * @throws Pack200Exception
+ * if there is a problem unpacking
+ * @throws IOException
+ * if there is a problem with I/O during unpacking
+ */
+ public void unpack(InputStream in, JarOutputStream out) throws IOException,
+ Pack200Exception {
+ if (!in.markSupported())
+ in = new BufferedInputStream(in);
+ // TODO Can handle multiple concatenated streams, so should deal with
+ // that possibility
+ parse(in).unpack(in, out);
+ }
+
+ /**
+ * 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
+ */
+ protected void debug(String message) {
+ if (System.getProperty("debug.pack200") != null) {
+ System.err.println(message);
+ }
+ }
- // 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;
- }
- /**
- * 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 {
- in.mark(count * codec.getB());
- long[] result = codec.decode(count, in);
- if (result.length > 0 && !codec.equals(Codec.BYTE1)) {
- int first = (int) result[0];
- if (codec.isSigned() && first >= -256 && first <= -1) {
- Codec weShouldHaveUsed = CodecEncoding.getCodec(-1 - first,
- getBandHeadersInputStream(), codec);
- in.reset();
- result = weShouldHaveUsed.decode(count, in);
- } else if (!codec.isSigned() && first >= codec.getL()
- && first <= codec.getL() + 255) {
- Codec weShouldHaveUsed = CodecEncoding.getCodec(first
- - codec.getL(), getBandHeadersInputStream(), codec);
- in.reset();
- result = weShouldHaveUsed.decode(count, in);
- }
- }
- // TODO Remove debugging code
- debug("Parsed *" + name + " (" + result.length + ")");
- return result;
- }
/**
- * Decode a scalar from the band file. A scalar is like a band, but does not
- * perform any band code switching.
+ * Writes the segment to an output stream. The output stream should be
+ * pre-buffered for efficiency. Also takes the same input stream for
+ * reading, since the file bits may not be loaded and thus just copied from
+ * one stream to another. Doesn't close the output stream when finished, in
+ * case there are more entries (e.g. further segments) to be written.
*
- * @param name
- * the name of the scalar (primarily for logging/debugging
- * purposes)
+ * @param out
+ * the JarOutputStream to write data to
* @param in
- * the input stream to read from
- * @param codec
- * the codec for this scalar
- * @return the decoded value
+ * the same InputStream that was used to parse the segment
* @throws IOException
- * if there is a problem reading from the underlying input
- * stream
+ * if an error occurs whilst reading or writing to the streams
* @throws Pack200Exception
- * if there is a problem decoding the value or that the value is
- * invalid
+ * if an error occurs whilst unpacking data
*/
- private long decodeScalar(String name, InputStream in, BHSDCodec codec)
+ public void writeJar(JarOutputStream out, InputStream in)
throws IOException, Pack200Exception {
- debug("Parsed #" + name + " (1)");
- return codec.decode(in);
- }
-
- /**
- * 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;
- }
-
- public long getArchiveSize() {
- return archiveSize;
- }
+ fileBands.processFileBits(in);
+ DataOutputStream dos = new DataOutputStream(out);
+ String[] fileName = fileBands.getFileName();
+ long[] fileModtime = fileBands.getFileModtime();
+ long[] fileOptions = fileBands.getFileOptions();
+ long[] fileSize = fileBands.getFileSize();
+ byte[][] fileBits = fileBands.getFileBits();
+
+ // out.setLevel(JarEntry.DEFLATED)
+ // now write the files out
+ int classNum = 0;
+ int numberOfFiles = header.getNumberOfFiles();
+ long archiveModtime = header.getArchiveModtime();
+ SegmentOptions options = header.getOptions();
+ for (int i = 0; i < numberOfFiles; i++) {
+ String name = fileName[i];
+ long modtime = archiveModtime + fileModtime[i];
+ boolean deflate = (fileOptions[i] & 1) == 1
+ || options.shouldDeflate();
+ boolean isClass = (fileOptions[i] & 2) == 2 || name == null
+ || name.equals("");
+ if (isClass) {
+ // pull from headers
+ if (name == null || name.equals(""))
+ name = classBands.getClassThis()[classNum] + ".class";
+ }
+ JarEntry entry = new JarEntry(name);
+ if (deflate)
+ entry.setMethod(JarEntry.DEFLATED);
+ entry.setTime(modtime);
+ out.putNextEntry(entry);
- /**
- * 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]);
+ if (isClass) {
+ // write to dos
+ ClassFile classFile = buildClassFile(classNum);
+ classFile.write(dos);
+ dos.flush();
+ classNum++;
+ } else {
+ long size = fileSize[i];
+ entry.setSize(size);
+ // TODO pull from in
+ byte[] data = fileBits[i];
+ out.write(data);
+ }
}
- return bandHeadersInputStream;
-
- }
-
- public SegmentConstantPool getConstantPool() {
- return pool;
- }
-
- public int getNumberOfFiles() {
- return numberOfFiles;
- }
-
- private SegmentOptions getOptions() {
- return options;
- }
-
- public int getSegmentsRemaining() {
- return segmentsRemaining;
+ dos.flush();
+ out.finish();
+ out.flush();
}
- private void parseArchiveFileCounts(InputStream in) throws IOException,
- Pack200Exception {
- if (getOptions().hasArchiveFileCounts()) {
- 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));
- }
- }
+ public SegmentConstantPool getConstantPool() {
+ return cpBands.getConstantPool();
+ }
- private void parseArchiveSpecialCounts(InputStream in) throws IOException,
- Pack200Exception {
- if (getOptions().hasSpecialFormats()) {
- setBandHeadersSize(decodeScalar("band_headers_size", in,
- Codec.UNSIGNED5));
- setAttributeDefinitionCount(decodeScalar("attr_definition_count",
- in, Codec.UNSIGNED5));
- }
- }
- /**
- * Reads {@link #attributeDefinitionCount} attribute definitions from the
- * stream, into {@link #attributeDefinitionHeader},
- * {@link #attributeDefinitionName} and {@link #attributeDefinitionLayout}.
- * This affects the codecs that are used to parse non-standard bands. TODO
- * Currently, these values if present cause a failure in the parsing.
- *
- * @param in
- * the input stream to read from
- * @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 void parseAttributeDefinition(InputStream in) throws IOException,
- Pack200Exception {
- 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");
- attributeDefinitionMap = new AttributeLayoutMap();
- }
+ public SegmentHeader getSegmentHeader() {
+ return header;
+ }
- /**
- * @param in
- * @throws Pack200Exception
- * @throws IOException
- */
- private void parseAttributeMethodExceptions(InputStream in)
- throws Pack200Exception, IOException {
- // TODO Should refactor this stuff into the layout somehow
- AttributeLayout layout = attributeDefinitionMap.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)) {
- // TODO This should be a decoeBand ...
- numExceptions[i][j] = (int) codec.decode(in);
- }
- }
- }
- for (int i = 0; i < classCount; i++) {
- 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(cpClass[(int) result]);
- }
- }
- methodExceptions[i][j] = new ExceptionsAttribute(exceptions);
- methodAttributes[i][j].add(methodExceptions[i][j]);
- }
- }
- }
- }
- /**
- * @param in
- *
- */
- private void parseAttributeMethodSignature(InputStream in)
- throws Pack200Exception, IOException {
- parseAttributeUnknown(AttributeLayout.ATTRIBUTE_SIGNATURE,
- AttributeLayout.CONTEXT_METHOD, methodFlags);
- }
+ protected AttrDefinitionBands getAttrDefinitionBands() {
+ return attrDefinitionBands;
+ }
- /**
- * @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 = attributeDefinitionMap.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)");
- }
- private void parseBcBands(InputStream in) throws IOException,
- Pack200Exception {
- int bcStringRefCount = 0;
- int bcInitRefCount = 0;
- int bcFieldRefCount = 0;
- int bcThisFieldCount = 0;
- int bcMethodRefCount = 0;
- int bcIMethodRefCount = 0;
+ protected BcBands getBcBands() {
+ return bcBands;
+ }
- AttributeLayout abstractModifier = attributeDefinitionMap
- .getAttributeLayout(AttributeLayout.ACC_ABSTRACT,
- AttributeLayout.CONTEXT_METHOD);
- AttributeLayout nativeModifier = attributeDefinitionMap
- .getAttributeLayout(AttributeLayout.ACC_NATIVE,
- AttributeLayout.CONTEXT_METHOD);
- AttributeLayout staticModifier = attributeDefinitionMap
- .getAttributeLayout(AttributeLayout.ACC_STATIC,
- AttributeLayout.CONTEXT_METHOD);
- methodByteCodePacked = new byte[classCount][][];
- int bcParsed = 0;
- for (int c = 0; c < classCount; c++) {
- int numberOfMethods = methodFlags[c].length;
- methodByteCodePacked[c] = new byte[numberOfMethods][];
- for (int m = 0; m < numberOfMethods; m++) {
- long methodFlag = methodFlags[c][m];
- if (!abstractModifier.matches(methodFlag)
- && !nativeModifier.matches(methodFlag)) {
- ByteArrayOutputStream codeBytes = new ByteArrayOutputStream();
- byte code;
- while ((code = (byte) (0xff & in.read())) != -1)
- codeBytes.write(code);
- methodByteCodePacked[c][m] = codeBytes.toByteArray();
- bcParsed += methodByteCodePacked[c][m].length;
- for (int i = 0; i < methodByteCodePacked[c][m].length; i++) {
- int codePacked = 0xff & methodByteCodePacked[c][m][i];
- // TODO a lot of this needs to be encapsulated in the
- // place that
- // calculates what the arguments are, since (a) it will
- // need
- // to know where to get them, and (b) what to do with
- // them
- // once they've been gotten. But that's for another
- // time.
- switch (codePacked) {
- case 18: // (a)ldc
- bcStringRefCount++;
- break;
- case 178: // getstatic
- case 179: // putstatic
- case 180: // getfield
- case 181: // putfield
- bcFieldRefCount++;
- break;
- case 182: // invokevirtual
- case 183: // invokespecial
- case 184: // invokestatic
- bcMethodRefCount++;
- break;
- case 185: // invokeinterface
- bcIMethodRefCount++;
- break;
- case 202: // getstatic_this
- case 203: // putstatic_this
- case 204: // getfield_this
- case 205: // putfield_this
- bcThisFieldCount++;
- break;
- case 231: // invoke_special_init
- bcInitRefCount++;
- break;
- default: // unhandled specifically at this stage
- debug("Found unhandled "
- + ByteCode.getByteCode(codePacked));
- }
- }
- }
- }
- }
- // other bytecode bands
- debug("Parsed *bc_codes (" + bcParsed + ")");
- debug("unimplemented bc_case_count");
- debug("unimplemented bc_case_value");
- debug("unimplemented bc_byte");
- debug("unimplemented bc_short");
- debug("unimplemented bc_local");
- debug("unimplemented bc_label");
- debug("unimplemented bc_intref");
- debug("unimplemented bc_floatref");
- debug("unimplemented bc_longref");
- debug("unimplemented bc_doubleref");
- int[] bcStringRef = decodeBandInt("bc_stringref", in, Codec.DELTA5,
- bcStringRefCount);
- debug("unimplemented bc_classref");
- int[] bcFieldRef = decodeBandInt("bc_fieldref", in, Codec.DELTA5,
- bcFieldRefCount);
- int[] bcMethodRef = decodeBandInt("bc_methodref", in, Codec.UNSIGNED5,
- bcMethodRefCount);
- int[] bcIMethodRef = decodeBandInt("bc_imethodref", in, Codec.DELTA5,
- bcIMethodRefCount);
- int[] bcThisField = decodeBandInt("bc_thisfield", in, Codec.UNSIGNED5,
- bcThisFieldCount);
- debug("unimplemented bc_superfield");
- debug("unimplemented bc_thismethod");
- debug("unimplemented bc_supermethod");
- debug("unimplemented bc_initref");
- int[] bcInitRef = decodeBandInt("bc_initref", in, Codec.UNSIGNED5,
- bcInitRefCount);
- debug("unimplemented bc_escref");
- debug("unimplemented bc_escrefsize");
- debug("unimplemented bc_escsize");
- debug("unimplemented bc_escbyte");
- int i = 0;
- for (int c = 0; c < classCount; c++) {
- int numberOfMethods = methodFlags[c].length;
- for (int m = 0; m < numberOfMethods; m++) {
- long methodFlag = methodFlags[c][m];
- if (!abstractModifier.matches(methodFlag)
- && !nativeModifier.matches(methodFlag)) {
- int maxStack = codeMaxStack[i];
- int maxLocal = codeMaxNALocals[i];
- if (!staticModifier.matches(methodFlag))
- maxLocal++; // one for 'this' parameter
- maxLocal += SegmentUtils.countArgs(methodDescr[c][m]);
- // TODO Move creation of code attribute until after constant
- // pool resolved
- CodeAttribute attr = new CodeAttribute(maxStack, maxLocal,
- methodByteCodePacked[c][m]);
- methodAttributes[c][m].add(attr);
- i++;
- }
- }
- }
+ protected ClassBands getClassBands() {
+ return classBands;
+ }
- }
- 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");
- AttributeLayout layout = attributeDefinitionMap.getAttributeLayout(
- AttributeLayout.ATTRIBUTE_SOURCE_FILE,
- AttributeLayout.CONTEXT_CLASS);
- for (int i = 0; i < classCount; i++) {
- long flag = classFlags[i];
- if (layout.matches(flag)) {
- // 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, this);
- debug("Processed value " + value + " for SourceFile");
- }
- }
- debug("unimplemented class_EnclosingMethod_RC");
- debug("unimplemented class_EnclosingMethod_RDN");
- debug("unimplemented class_Signature_RS");
- parseMetadataBands(AttributeLayout.CONTEXT_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");
- }
+ protected CpBands getCpBands() {
+ return cpBands;
+ }
- private void parseClassBands(InputStream in) throws IOException,
- Pack200Exception {
- classThis = parseReferences("class_this", in, Codec.DELTA5, classCount,
- cpClass);
- classSuper = parseReferences("class_super", in, Codec.DELTA5,
- classCount, cpClass);
- classInterfaces = new String[classCount][];
- int[] classInterfaceLengths = decodeBandInt("class_interface_count",
- in, Codec.DELTA5, classCount);
- classInterfaces = parseReferences("class_interface", in, Codec.DELTA5,
- classCount, classInterfaceLengths, cpClass);
- classFieldCount = decodeBandInt("class_field_count", in, Codec.DELTA5,
- classCount);
- classMethodCount = decodeBandInt("class_method_count", in,
- Codec.DELTA5, classCount);
- parseFieldBands(in);
- parseMethodBands(in);
- parseClassAttrBands(in);
- parseCodeBands(in);
- }
- 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));
- }
+ protected FileBands getFileBands() {
+ return fileBands;
+ }
- 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");
- }
- }
- private void parseCodeBands(InputStream in) throws Pack200Exception,
- IOException {
- AttributeLayout layout = attributeDefinitionMap.getAttributeLayout(
- AttributeLayout.ATTRIBUTE_CODE, AttributeLayout.CONTEXT_METHOD);
+ protected SegmentHeader getHeader() {
+ return header;
+ }
- int codeBands = SegmentUtils.countMatches(methodFlags, layout);
- int[] codeHeaders = decodeBandInt("code_headers", in, Codec.BYTE1,
- codeBands);
- int codeSpecialHeader = 0;
- for (int i = 0; i < codeBands; i++) {
- if (codeHeaders[i] == 0)
- codeSpecialHeader++;
- }
- int[] codeMaxStackSpecials = decodeBandInt("code_max_stack", in,
- Codec.UNSIGNED5, codeSpecialHeader);
- int[] codeMaxNALocalsSpecials = decodeBandInt("code_max_na_locals", in,
- Codec.UNSIGNED5, codeSpecialHeader);
- int[] codeHandlerCountSpecials = decodeBandInt("code_handler_count",
- in, Codec.UNSIGNED5, codeSpecialHeader);
- codeMaxStack = new int[codeBands];
- codeMaxNALocals = new int[codeBands];
- codeHandlerCount = new int[codeBands];
- int special = 0;
- for (int i = 0; i < codeBands; i++) {
- int header = 0xff & codeHeaders[i];
- if (header < 0) {
- throw new IllegalStateException("Shouldn't get here");
- } else if (header == 0) {
- codeMaxStack[i] = codeMaxStackSpecials[special];
- codeMaxNALocals[i] = codeMaxNALocalsSpecials[special];
- codeHandlerCount[i] = codeHandlerCountSpecials[special];
- special++;
- } else if (header <= 144) {
- codeMaxStack[i] = (header - 1) % 12;
- codeMaxNALocals[i] = (header - 1) / 12;
- codeHandlerCount[i] = 0;
- } else if (header <= 208) {
- codeMaxStack[i] = (header - 145) % 8;
- codeMaxNALocals[i] = (header - 145) / 8;
- codeHandlerCount[i] = 1;
- } else if (header <= 255) {
- codeMaxStack[i] = (header - 209) % 7;
- codeMaxNALocals[i] = (header - 209) / 7;
- codeHandlerCount[i] = 2;
- } else {
- throw new IllegalStateException("Shouldn't get here either");
- }
- }
- 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);
- }
+ protected IcBands getIcBands() {
+ return icBands;
+ }
- /**
- * Parses the constant pool class names, using {@link #cpClassCount} to
- * populate {@link #cpClass} from {@link #cpUTF8}.
- *
- * @param in
- * the input stream to read from
- * @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 void parseCpClass(InputStream in) throws IOException,
- Pack200Exception {
- cpClass = parseReferences("cp_Class", in, Codec.UDELTA5, cpClassCount,
- cpUTF8);
- }
-
- private void parseCpCounts(InputStream in) throws IOException,
- Pack200Exception {
- setCPUtf8Count(decodeScalar("cp_Utf8_count", in, Codec.UNSIGNED5));
- if (getOptions().hasCPNumberCounts()) {
- 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(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));
- }
-
- /**
- * Parses the constant pool descriptor definitions, using
- * {@link #cpDescriptorCount} to populate {@link #cpDescriptor}. For ease
- * of use, the cpDescriptor is stored as a string of the form name:type,
- * largely to make it easier for representing field and method descriptors
- * (e.g. out:java.lang.PrintStream) in a way that is
- * compatible with passing String arrays.
- *
- * @param in
- * the input stream to read from
- * @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 void parseCpDescriptor(InputStream in) throws IOException,
- Pack200Exception {
- 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]; //$NON-NLS-1$
- }
- }
-
- private void parseCpDouble(InputStream in) throws IOException,
- Pack200Exception {
- cpDouble = new double[cpDoubleCount];
- 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++) {
- cpDouble[i] = Double.longBitsToDouble(hiBits[i] << 32 | loBits[i]);
- }
- }
-
- /**
- * Parses the constant pool field definitions, using {@link #cpFieldCount}
- * to populate {@link #cpFieldClass} and {@link #cpFieldDescriptor}.
- *
- * @param in
- * the input stream to read from
- * @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 void parseCpField(InputStream in) throws IOException,
- Pack200Exception {
- 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];
- int floatBits[] = decodeBandInt("cp_Float", in, Codec.UDELTA5,
- cpFloatCount);
- for (int i = 0; i < cpFloatCount; i++) {
- cpFloat[i] = Float.intBitsToFloat(floatBits[i]);
- }
- }
-
- /**
- * Parses the constant pool interface method definitions, using
- * {@link #cpIMethodCount} to populate {@link #cpIMethodClass} and
- * {@link #cpIMethodDescriptor}.
- *
- * @param in
- * the input stream to read from
- * @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 void parseCpIMethod(InputStream in) throws IOException,
- Pack200Exception {
- 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,
- Pack200Exception {
- cpInt = new int[cpIntCount];
- long last = 0;
- for (int i = 0; i < cpIntCount; i++) {
- last = Codec.UDELTA5.decode(in, last);
- cpInt[i] = (int) last;
- }
- }
-
- private void parseCpLong(InputStream in) throws IOException,
- Pack200Exception {
- cpLong = parseFlags("cp_Long", in, cpLongCount, new int[] { 1 },
- Codec.UDELTA5, Codec.DELTA5)[0];
- }
-
- /**
- * Parses the constant pool method definitions, using {@link #cpMethodCount}
- * to populate {@link #cpMethodClass} and {@link #cpMethodDescriptor}.
- *
- * @param in
- * the input stream to read from
- * @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 void parseCpMethod(InputStream in) throws IOException,
- Pack200Exception {
- cpMethodClass = parseReferences("cp_Method_class", in, Codec.DELTA5,
- cpMethodCount, cpClass);
- cpMethodDescriptor = parseReferences("cp_Method_desc", in,
- Codec.UDELTA5, cpMethodCount, cpDescriptor);
- }
-
- /**
- * Parses the constant pool signature classes, using
- * {@link #cpSignatureCount} to populate {@link #cpSignature}. A signature
- * form is akin to the bytecode representation of a class; Z for boolean, I
- * for int, [ for array etc. However, although classes are started with L,
- * the classname does not follow the form; instead, there is a separate
- * array of classes. So an array corresponding to
- * public static void main(String args[]) has a form of
- * [L(V) and a classes array of
- * [java.lang.String]. The {@link #cpSignature} is a string
- * representation identical to the bytecode equivalent
- * [Ljava/lang/String;(V) TODO Check that the form is as
- * above and update other types e.g. J
- *
- * @param in
- * the input stream to read from
- * @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 void parseCpSignature(InputStream in) throws IOException,
- Pack200Exception {
- 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++) {
- String form = cpSignatureForm[i];
- int len = form.length();
- StringBuffer signature = new StringBuffer(64);
- ArrayList list = new ArrayList();
- for (int j = 0; j < len; j++) {
- char c = form.charAt(j);
- signature.append(c);
- if (c == 'L') {
- int index = (int) (last = Codec.UDELTA5.decode(in, last));
- String className = cpClass[index];
- list.add(className);
- signature.append(className);
- }
- }
- cpSignature[i] = signature.toString();
- }
- }
-
- /**
- * Parses the constant pool strings, using {@link #cpStringCount} to
- * populate {@link #cpString} from indexes into {@link #cpUTF8}.
- *
- * @param in
- * the input stream to read from
- * @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 void parseCpString(InputStream in) throws IOException,
- Pack200Exception {
- cpString = new String[cpStringCount];
- long last = 0;
- for (int i = 0; i < cpStringCount; i++) {
- int index = (int) (last = Codec.UDELTA5.decode(in, last));
- cpString[i] = cpUTF8[index];
- }
- }
-
- private void parseCpUtf8(InputStream in) throws IOException,
- Pack200Exception {
- // TODO Update codec.decode -> decodeScalar
- cpUTF8 = new String[cpUTF8Count];
- cpUTF8[0] = ""; //$NON-NLS-1$
- int[] prefix = new int[cpUTF8Count];
- int[] suffix = new int[cpUTF8Count];
- if (cpUTF8Count > 0) {
- prefix[0] = 0;
- suffix[0] = 0;
- if (cpUTF8Count > 1)
- prefix[1] = 0;
- }
- long last = 0;
- for (int i = 2; i < cpUTF8Count; i++) {
- last = prefix[i] = (int) Codec.DELTA5.decode(in, last);
- }
- int chars = 0;
- int bigSuffix = 0;
- for (int i = 1; i < cpUTF8Count; i++) {
- last = suffix[i] = (int) Codec.UNSIGNED5.decode(in);
- if (last == 0) {
- bigSuffix++;
- } else {
- chars += last;
- }
- }
- char data[] = new char[chars];
- for (int i = 0; i < data.length; i++) {
- data[i] = (char) Codec.CHAR3.decode(in);
- }
- // read in the big suffix data
- char bigSuffixData[][] = new char[bigSuffix][];
- last = 0;
- for (int i = 0; i < bigSuffix; i++) {
- last = (int) Codec.DELTA5.decode(in, last);
- bigSuffixData[i] = new char[(int) last];
- }
- // initialize big suffix data
- for (int i = 0; i < bigSuffix; i++) {
- char[] singleBigSuffixData = bigSuffixData[i];
- last = 0;
- for (int j = 0; j < singleBigSuffixData.length; j++) {
- last = singleBigSuffixData[j] = (char) Codec.DELTA5.decode(in,
- last);
- }
- }
- // go through the strings
- chars = 0;
- bigSuffix = 0;
- for (int i = 1; i < cpUTF8Count; i++) {
- String lastString = cpUTF8[i - 1];
- if (suffix[i] == 0) {
- // The big suffix stuff hasn't been tested, and I'll be
- // surprised if it works first time w/o errors ...
- cpUTF8[i] = lastString.substring(0, prefix[i])
- + new String(bigSuffixData[bigSuffix++]);
- } else {
- cpUTF8[i] = lastString.substring(0, prefix[i])
- + new String(data, chars, suffix[i]);
- chars += suffix[i];
- }
- }
- }
-
- private void parseFieldBands(InputStream in) throws IOException,
- Pack200Exception {
- fieldDescr = parseReferences("field_descr", in, Codec.DELTA5,
- classCount, classFieldCount, cpDescriptor);
- fieldFlags = parseFlags("field_flags", in, classCount, classFieldCount,
- 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");
- AttributeLayout layout = attributeDefinitionMap.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, this);
- fieldAttributes[i][j]
- .add(new ConstantValueAttribute(value));
- debug("Processed value " + value + " for ConstantValue");
- }
- }
- }
- debug("unimplemented field_Signature_RS");
- parseMetadataBands(AttributeLayout.CONTEXT_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
- * start of the file_bits themselves, and there will be Sum(file_size) bits
- * remaining in the stream with BYTE1 compression. A decent implementation
- * will probably just stream the bytes out to the reconstituted Jar rather
- * than caching them.
- *
- * @param in
- * the input stream to read from
- * @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 void parseFileBands(InputStream in) throws IOException,
- Pack200Exception {
- // if (false && System.getProperty("debug.pack200") != null) {
- // // TODO HACK
- // fileSize = new long[numberOfFiles];
- // fileModtime = new long[numberOfFiles];
- // fileOptions = new long[numberOfFiles];
- // fileName = new String[numberOfFiles];
- // Arrays.fill(fileName, "");
- // return;
- // }
- 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];
- if (options.hasFileModtime()) {
- last = 0;
- for (int i = 0; i < numberOfFiles; i++) {
- fileModtime[i] |= (last = Codec.DELTA5.decode(in, last));
- }
- }
- fileOptions = new long[numberOfFiles];
- if (options.hasFileOptions()) {
- last = 0;
- for (int i = 0; i < numberOfFiles; i++) {
- fileOptions[i] |= (last = Codec.UNSIGNED5.decode(in, last));
- }
- }
- }
-
- private long[] parseFlags(String name, InputStream in, int count,
- Codec codec, boolean hasHi) throws IOException, Pack200Exception {
- return parseFlags(name, in, 1, new int[] { count }, (hasHi ? codec
- : null), codec)[0];
- }
-
- private long[][] parseFlags(String name, InputStream in, int count,
- int counts[], Codec codec, boolean hasHi) throws IOException,
- Pack200Exception {
- return parseFlags(name, in, count, counts, (hasHi ? codec : null),
- codec);
- }
-
- private long[][] parseFlags(String name, InputStream in, int count,
- int counts[], Codec hiCodec, Codec loCodec) throws IOException,
- Pack200Exception {
- // TODO Move away from decoding into a parseBand type structure
- if (count == 0) {
- return new long[][] { {} };
- }
- long[][] result = new long[count][];
- // TODO What happens when the decode here indicates a different
- // encoding?
- // TODO Move this to a decodeBandInt
- long last = 0;
- for (int j = 0; j < count; j++) {
- result[j] = new long[counts[j]];
- for (int i = 0; i < counts[j] && hiCodec != null; i++) {
- last = hiCodec.decode(in, last);
- result[j][i] = last << 32;
- }
- }
- last = 0;
- for (int j = 0; j < count; j++)
- for (int i = 0; i < counts[j]; i++) {
- last = loCodec.decode(in, last);
- result[j][i] = result[j][i] | last;
- }
- // TODO Remove debugging code
- debug("Parsed *" + name + " (" + result.length + ")");
- return result;
- }
-
- private void parseIcBands(InputStream in) throws IOException,
- Pack200Exception {
- 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("ic_outer_class", in, Codec.DELTA5,
- outerClasses, cpClass);
- icName = parseReferences("ic_name", in, Codec.DELTA5, outerClasses,
- cpUTF8);
- }
-
- private void parseMetadataBands(int context) throws Pack200Exception {
- String[] RxA;
- if (AttributeLayout.CONTEXT_METHOD == context) {
- RxA = new String[] { "RVA", "RIA", "RVPA", "RIPA", "AD" };
- } else if (AttributeLayout.CONTEXT_FIELD == context
- || AttributeLayout.CONTEXT_CLASS == context) {
- RxA = new String[] { "RVA", "RIA" };
- } else {
- throw new Pack200Exception("Unknown type of metadata unit "
- + context);
- }
- // AttributeLayout layout =
- // map.get(RuntimeVisibleAnnotations,class/field/method as int)
- // foreachheader ...
- // if layout.matches(header[n] or whatever)
- String contextName = (AttributeLayout.CONTEXT_METHOD == context ? "method"
- : (AttributeLayout.CONTEXT_FIELD == context ? "field"
- : (AttributeLayout.CONTEXT_CLASS == context ? "class"
- : "unkowon")));
- for (int i = 0; i < RxA.length; i++) {
- String rxa = RxA[i];
- if (rxa.indexOf("P") >= 0) {
- debug("unimplemented " + contextName + "_" + rxa + "_param_NB");
- }
- if (!rxa.equals("AD")) {
- debug("unimplemented " + contextName + "_" + rxa + "_anno_N");
- debug("unimplemented " + contextName + "_" + rxa + "_type_RS");
- debug("unimplemented " + contextName + "_" + rxa + "_pair_N");
- debug("unimplemented " + contextName + "_" + rxa + "_name_RU");
- }
- debug("unimplemented " + contextName + "_" + rxa + "_T");
- debug("unimplemented " + contextName + "_" + rxa + "_caseI_KI");
- debug("unimplemented " + contextName + "_" + rxa + "_caseD_KD");
- debug("unimplemented " + contextName + "_" + rxa + "_caseF_KF");
- debug("unimplemented " + contextName + "_" + rxa + "_caseJ_KJ");
- debug("unimplemented " + contextName + "_" + rxa + "_casec_RS");
- debug("unimplemented " + contextName + "_" + rxa + "_caseet_RS");
- debug("unimplemented " + contextName + "_" + rxa + "_caseec_RU");
- debug("unimplemented " + contextName + "_" + rxa + "_cases_RU");
- debug("unimplemented " + contextName + "_" + rxa + "_casearray_N");
- debug("unimplemented " + contextName + "_" + rxa + "_nesttype_RS");
- debug("unimplemented " + contextName + "_" + rxa + "_nestpair_N");
- debug("unimplemented " + contextName + "_" + rxa + "_nestname_RU");
- }
- }
-
- private void parseMethodBands(InputStream in) throws IOException,
- Pack200Exception {
- methodDescr = parseReferences("method_descr", in, Codec.MDELTA5,
- classCount, classMethodCount, cpDescriptor);
- methodFlags = parseFlags("method_flags", in, classCount,
- 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];
- 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");
- // assign empty method attributes
- methodAttributes = new ArrayList[classCount][];
- for (int i = 0; i < classCount; i++) {
- methodAttributes[i] = new ArrayList[methodFlags[i].length];
- for (int j = 0; j < methodFlags[i].length; j++) {
- methodAttributes[i][j] = new ArrayList();
- }
- }
- parseAttributeMethodExceptions(in);
- parseAttributeMethodSignature(in);
- parseMetadataBands(AttributeLayout.CONTEXT_METHOD);
- }
-
- /**
- * Helper method to parse count references from in,
- * using codec to decode the values as indexes into
- * reference (which is populated prior to this call). An
- * exception is thrown if a decoded index falls outside the range
- * [0..reference.length-1]. Unlike the other parseReferences, this
- * post-processes the result into an array of results.
- *
- * @param name
- * TODO
- * @param in
- * the input stream to read from
- * @param codec
- * the codec to use for decoding
- * @param count
- * the number of references to decode
- * @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(String name, InputStream in,
- BHSDCodec codec, int count, int counts[], String[] reference)
- throws IOException, Pack200Exception {
- if (count == 0) {
- return new String[][] { {} };
- }
- String[][] result = new String[count][];
- int sum = 0;
- for (int i = 0; i < count; i++) {
- result[i] = new String[counts[i]];
- sum += counts[i];
- }
- // TODO Merge the decode and parsing of a multiple structure into one
- String[] result1 = new String[sum];
- int[] decode = decodeBandInt(name, in, codec, sum);
- for (int i1 = 0; i1 < sum; i1++) {
- int index = decode[i1];
- if (index < 0 || index >= reference.length)
- throw new Pack200Exception(
- "Something has gone wrong during parsing references");
- result1[i1] = reference[index];
- }
- String[] refs = result1;
- // TODO Merge the decode and parsing of a multiple structure into one
- int pos = 0;
- for (int i = 0; i < count; i++) {
- int num = counts[i];
- result[i] = new String[num];
- System.arraycopy(refs, pos, result[i], 0, num);
- pos += num;
- }
- return result;
- }
-
- /**
- * Helper method to parse count references from in,
- * using codec to decode the values as indexes into
- * reference (which is populated prior to this call). An
- * 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
- * the codec to use for decoding
- * @param count
- * the number of references to decode
- * @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(String name, InputStream in,
- BHSDCodec codec, int count, String[] reference) throws IOException,
- Pack200Exception {
- return parseReferences(name, in, codec, 1, new int[] { count },
- reference)[0];
- }
-
- /**
- * This performs the actual work of parsing against a non-static instance of
- * Segment.
- *
- * @param in
- * the input stream to read from
- * @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 void parseSegment(InputStream in) throws IOException,
- Pack200Exception {
- debug("-------");
- parseSegmentHeader(in);
- if (bandHeadersSize > 0) {
- byte[] bandHeaders = new byte[(int) bandHeadersSize];
- readFully(in, bandHeaders);
- setBandHeadersData(bandHeaders);
- }
- parseCpUtf8(in);
- parseCpInt(in);
- parseCpFloat(in);
- parseCpLong(in);
- parseCpDouble(in);
- parseCpString(in);
- parseCpClass(in);
- parseCpSignature(in);
- parseCpDescriptor(in);
- parseCpField(in);
- parseCpMethod(in);
- parseCpIMethod(in);
- parseAttributeDefinition(in);
- parseIcBands(in);
- parseClassBands(in);
- parseBcBands(in);
- parseFileBands(in);
- }
-
- 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 (word[m] != magic[m])
- throw new Error("Bad header");
- setArchiveMinorVersion((int) decodeScalar("archive_minver", in,
- Codec.UNSIGNED5));
- setArchiveMajorVersion((int) decodeScalar("archive_majver", in,
- Codec.UNSIGNED5));
- setOptions(new SegmentOptions((int) decodeScalar("archive_options", in,
- Codec.UNSIGNED5)));
- parseArchiveFileCounts(in);
- parseArchiveSpecialCounts(in);
- parseCpCounts(in);
- parseClassCounts(in);
- }
-
- private void processFileBits(InputStream in) throws IOException,
- Pack200Exception {
- // now read in the bytes
- fileBits = new byte[numberOfFiles][];
- for (int i = 0; i < numberOfFiles; i++) {
- int size = (int) fileSize[i];
- // TODO This buggers up if file_size > 2^32. Probably an array is
- // not the right choice, and
- // we should just serialize the bugger here?
- fileBits[i] = new byte[size];
- for (int j = 0; j < size; j++) {
- fileBits[i][j] = (byte) Codec.BYTE1.decode(in);
- }
- }
- }
-
- /**
- * Sets the major version of this archive.
- *
- * @param version
- * the minor version of the archive
- * @throws Pack200Exception
- * if the major version is not 150
- */
- private void setArchiveMajorVersion(int version) throws Pack200Exception {
- if (version != 150)
- throw new Pack200Exception("Invalid segment major version");
- archiveMajor = version;
- }
-
- /**
- * Sets the minor version of this archive
- *
- * @param version
- * the minor version of the archive
- * @throws Pack200Exception
- * if the minor version is not 7
- */
- private void setArchiveMinorVersion(int version) throws Pack200Exception {
- if (version != 7)
- throw new Pack200Exception("Invalid segment minor version");
- archiveMinor = version;
- }
-
- public void setArchiveModtime(long archiveModtime) {
- this.archiveModtime = archiveModtime;
- }
-
- public void setArchiveSize(long archiveSize) {
- this.archiveSize = archiveSize;
- }
-
- private void setAttributeDefinitionCount(long valuie) {
- this.attributeDefinitionCount = (int) valuie;
- }
-
- private void setBandHeadersData(byte[] bandHeaders) {
- this.bandHeadersInputStream = new ByteArrayInputStream(bandHeaders);
- }
-
- private void setBandHeadersSize(long value) {
- this.bandHeadersSize = (int) value;
- }
-
- private void setClassCount(long value) {
- classCount = (int) value;
- }
-
- private void setCPClassCount(long value) {
- cpClassCount = (int) value;
- }
-
- private void setCPDescriptorCount(long value) {
- cpDescriptorCount = (int) value;
- }
-
- private void setCPDoubleCount(long value) {
- cpDoubleCount = (int) value;
- }
-
- private void setCPFieldCount(long value) {
- cpFieldCount = (int) value;
- }
-
- private void setCPFloatCount(long value) {
- cpFloatCount = (int) value;
- }
-
- private void setCPIMethodCount(long value) {
- cpIMethodCount = (int) value;
- }
-
- private void setCPIntCount(long value) {
- cpIntCount = (int) value;
- }
-
- private void setCPLongCount(long value) {
- cpLongCount = (int) value;
- }
-
- private void setCPMethodCount(long value) {
- cpMethodCount = (int) value;
- }
-
- private void setCPSignatureCount(long value) {
- cpSignatureCount = (int) value;
- }
-
- private void setCPStringCount(long value) {
- cpStringCount = (int) value;
- }
-
- private void setCPUtf8Count(long value) {
- cpUTF8Count = (int) value;
- }
-
- private void setDefaultClassMajorVersion(long value) {
- defaultClassMajorVersion = (int) value;
- }
-
- private void setDefaultClassMinorVersion(long value) {
- defaultClassMinorVersion = (int) value;
- }
-
- private void setInnerClassCount(long value) {
- innerClassCount = (int) value;
- }
-
- public void setNumberOfFiles(long value) {
- numberOfFiles = (int) value;
- }
-
- private void setOptions(SegmentOptions options) {
- this.options = options;
- }
-
- public void setSegmentsRemaining(long value) {
- segmentsRemaining = (int) value;
- }
-
- /**
- * This is only here to provide a mechanism to turn off the warnings (and to
- * prevent anyone from accidentally removing them from the file)
- *
- * @deprecated this will be deleted in the future, once I've started to use
- * them
- *
- */
- int shutUpAboutTheStupidNotReadVariablesYetIHaventImplementedIt() {
- return archiveMajor + archiveMinor + cpLong.hashCode()
- + icName.hashCode() + icOuterClass.hashCode()
- + icThisClass.hashCode();
- }
-
- /**
- * Unpacks a packed stream (either .pack. or .pack.gz) into a corresponding
- * JarOuputStream.
- *
- * @throws Pack200Exception
- * if there is a problem unpacking
- * @throws IOException
- * if there is a problem with I/O during unpacking
- */
- public void unpack(InputStream in, JarOutputStream out) throws IOException,
- Pack200Exception {
- if (!in.markSupported())
- in = new BufferedInputStream(in);
- // TODO Can handle multiple concatenated streams, so should deal with
- // that possibility
- parse(in).unpack(in, out);
- }
-
- /**
- * Writes the segment to an output stream. The output stream should be
- * pre-buffered for efficiency. Also takes the same input stream for
- * reading, since the file bits may not be loaded and thus just copied from
- * one stream to another. Doesn't close the output stream when finished, in
- * case there are more entries (e.g. further segments) to be written.
- *
- * @param out
- * the JarOutputStream to write data to
- * @param in
- * the same InputStream that was used to parse the segment
- * @throws IOException
- * if an error occurs whilst reading or writing to the streams
- * @throws Pack200Exception
- * if an error occurs whilst unpacking data
- */
- public void writeJar(JarOutputStream out, InputStream in)
- throws IOException, Pack200Exception {
- processFileBits(in);
- DataOutputStream dos = new DataOutputStream(out);
- // out.setLevel(JarEntry.DEFLATED)
- // now write the files out
- int classNum = 0;
- for (int i = 0; i < numberOfFiles; i++) {
- String name = fileName[i];
- long modtime = archiveModtime + fileModtime[i];
- boolean deflate = (fileOptions[i] & 1) == 1
- || options.shouldDeflate();
- boolean isClass = (fileOptions[i] & 2) == 2 || name == null
- || name.equals("");
- if (isClass) {
- // pull from headers
- if (name == null || name.equals(""))
- name = classThis[classNum] + ".class";
- }
- JarEntry entry = new JarEntry(name);
- if (deflate)
- entry.setMethod(JarEntry.DEFLATED);
- entry.setTime(modtime);
- out.putNextEntry(entry);
-
- if (isClass) {
- // write to dos
- ClassFile classFile = buildClassFile(classNum);
- classFile.write(dos);
- dos.flush();
- classNum++;
- } else {
- long size = fileSize[i];
- entry.setSize(size);
- // TODO pull from in
- byte[] data = fileBits[i];
- out.write(data);
- }
- }
- dos.flush();
- out.finish();
- out.flush();
- }
}
Index: src/main/java/org/apache/harmony/pack200/AttrDefinitionBands.java
===================================================================
--- src/main/java/org/apache/harmony/pack200/AttrDefinitionBands.java
+++ src/main/java/org/apache/harmony/pack200/AttrDefinitionBands.java
@@ -0,0 +1,72 @@
+/*
+ * 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;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ *
+ */
+public class AttrDefinitionBands extends BandSet {
+
+ private int[] attributeDefinitionHeader;
+
+ private String[] attributeDefinitionLayout;
+
+ private String[] attributeDefinitionName;
+
+ private AttributeLayoutMap attributeDefinitionMap;
+
+ private String[] cpUTF8;
+
+ public AttrDefinitionBands(Segment segment) {
+ super(segment);
+ this.cpUTF8 = segment.getCpBands().getCpUTF8();
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.harmony.pack200.BandSet#pack(java.io.OutputStream)
+ */
+ public void pack(OutputStream outputStream) {
+ // TODO Auto-generated method stub
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.harmony.pack200.BandSet#unpack(java.io.InputStream)
+ */
+ public void unpack(InputStream in) throws IOException,
+ Pack200Exception {
+ int attributeDefinitionCount = header.getAttributeDefinitionCount();
+ 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");
+ attributeDefinitionMap = new AttributeLayoutMap();
+ }
+
+ public AttributeLayoutMap getAttributeDefinitionMap() {
+ return attributeDefinitionMap;
+ }
+
+}
Index: src/main/java/org/apache/harmony/pack200/BandSet.java
===================================================================
--- src/main/java/org/apache/harmony/pack200/BandSet.java
+++ src/main/java/org/apache/harmony/pack200/BandSet.java
@@ -0,0 +1,272 @@
+/*
+ * 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;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public abstract class BandSet {
+
+ public abstract void unpack(InputStream inputStream) throws IOException, Pack200Exception;
+
+ public abstract void pack(OutputStream outputStream);
+
+ protected Segment segment;
+
+ protected SegmentHeader header;
+
+ public BandSet(Segment segment) {
+ this.segment = segment;
+ this.header = segment.getSegmentHeader();
+ }
+
+ /**
+ * 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
+ */
+ public 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];
+
+ // 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;
+ }
+
+ /**
+ * 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
+ */
+ public long[] decodeBandLong(String name, InputStream in, BHSDCodec codec,
+ int count) throws IOException, Pack200Exception {
+ if (codec.getB() == 1 || count == 0) {
+ return codec.decode(count, in);
+ }
+ long[] getFirst = codec.decode(1, in);
+ if (getFirst.length == 0) {
+ return getFirst;
+ }
+ long first = getFirst[0];
+ if (codec.isSigned() && first >= -256 && first <= -1) {
+ // Non-default codec should be used
+ Codec nonDefaultCodec = CodecEncoding.getCodec((int) (-1 - first),
+ header.getBandHeadersInputStream(), codec);
+ return nonDefaultCodec.decode(count, in);
+ } else if (!codec.isSigned() && first >= codec.getL()
+ && first <= codec.getL() + 255) {
+ // Non-default codec should be used
+ Codec nonDefaultCodec = CodecEncoding.getCodec((int) first
+ - codec.getL(), header.getBandHeadersInputStream(), codec);
+ return nonDefaultCodec.decode(count, in);
+ } else {
+ // First element should not be discarded
+ return codec.decode(count - 1, in, first);
+ }
+ }
+
+ public long[] parseFlags(String name, InputStream in, int count,
+ Codec codec, boolean hasHi) throws IOException, Pack200Exception {
+ return parseFlags(name, in, 1, new int[] { count }, (hasHi ? codec
+ : null), codec)[0];
+ }
+
+ public long[][] parseFlags(String name, InputStream in, int count,
+ int counts[], Codec codec, boolean hasHi) throws IOException,
+ Pack200Exception {
+ return parseFlags(name, in, count, counts, (hasHi ? codec : null),
+ codec);
+ }
+
+ public long[][] parseFlags(String name, InputStream in, int count,
+ int counts[], Codec hiCodec, Codec loCodec) throws IOException,
+ Pack200Exception {
+ // TODO Move away from decoding into a parseBand type structure
+ if (count == 0) {
+ return new long[][] { {} };
+ }
+ long[][] result = new long[count][];
+ // TODO What happens when the decode here indicates a different
+ // encoding?
+ // TODO Move this to a decodeBandInt
+ long last = 0;
+ for (int j = 0; j < count; j++) {
+ result[j] = new long[counts[j]];
+ for (int i = 0; i < counts[j] && hiCodec != null; i++) {
+ last = hiCodec.decode(in, last);
+ result[j][i] = last << 32;
+ }
+ }
+ last = 0;
+ for (int j = 0; j < count; j++)
+ for (int i = 0; i < counts[j]; i++) {
+ last = loCodec.decode(in, last);
+ result[j][i] = result[j][i] | last;
+ }
+ // TODO Remove debugging code
+ debug("Parsed *" + name + " (" + result.length + ")");
+ return result;
+ }
+
+ /**
+ * Helper method to parse count references from in,
+ * using codec to decode the values as indexes into
+ * reference (which is populated prior to this call). An
+ * 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
+ * the codec to use for decoding
+ * @param count
+ * the number of references to decode
+ * @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
+ */
+ public String[] parseReferences(String name, InputStream in,
+ BHSDCodec codec, int count, String[] reference) throws IOException,
+ Pack200Exception {
+ return parseReferences(name, in, codec, 1, new int[] { count },
+ reference)[0];
+ }
+
+ /**
+ * Helper method to parse count references from in,
+ * using codec to decode the values as indexes into
+ * reference (which is populated prior to this call). An
+ * exception is thrown if a decoded index falls outside the range
+ * [0..reference.length-1]. Unlike the other parseReferences, this
+ * post-processes the result into an array of results.
+ *
+ * @param name
+ * TODO
+ * @param in
+ * the input stream to read from
+ * @param codec
+ * the codec to use for decoding
+ * @param count
+ * the number of references to decode
+ * @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
+ */
+ protected String[][] parseReferences(String name, InputStream in,
+ BHSDCodec codec, int count, int counts[], String[] reference)
+ throws IOException, Pack200Exception {
+ if (count == 0) {
+ return new String[][] { {} };
+ }
+ String[][] result = new String[count][];
+ int sum = 0;
+ for (int i = 0; i < count; i++) {
+ result[i] = new String[counts[i]];
+ sum += counts[i];
+ }
+ // TODO Merge the decode and parsing of a multiple structure into one
+ String[] result1 = new String[sum];
+ int[] decode = decodeBandInt(name, in, codec, sum);
+ for (int i1 = 0; i1 < sum; i1++) {
+ int index = decode[i1];
+ if (index < 0 || index >= reference.length)
+ throw new Pack200Exception(
+ "Something has gone wrong during parsing references");
+ result1[i1] = reference[index];
+ }
+ String[] refs = result1;
+ // TODO Merge the decode and parsing of a multiple structure into one
+ int pos = 0;
+ for (int i = 0; i < count; i++) {
+ int num = counts[i];
+ result[i] = new String[num];
+ System.arraycopy(refs, pos, result[i], 0, num);
+ pos += num;
+ }
+ return result;
+ }
+
+ /**
+ * 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
+ */
+ protected void debug(String message) {
+ if (System.getProperty("debug.pack200") != null) {
+ System.err.println(message);
+ }
+ }
+
+
+}
Index: src/main/java/org/apache/harmony/pack200/BcBands.java
===================================================================
--- src/main/java/org/apache/harmony/pack200/BcBands.java
+++ src/main/java/org/apache/harmony/pack200/BcBands.java
@@ -0,0 +1,198 @@
+/*
+ * 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;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+
+import org.apache.harmony.pack200.bytecode.ByteCode;
+import org.apache.harmony.pack200.bytecode.CodeAttribute;
+
+/**
+ *
+ */
+public class BcBands extends BandSet {
+
+ private byte[][][] methodByteCodePacked;
+
+ /**
+ * @param header
+ */
+ public BcBands(Segment segment) {
+ super(segment);
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.harmony.pack200.BandSet#pack(java.io.OutputStream)
+ */
+ public void pack(OutputStream outputStream) {
+ // TODO Auto-generated method stub
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.harmony.pack200.BandSet#unpack(java.io.InputStream)
+ */
+ public void unpack(InputStream in) throws IOException,
+ Pack200Exception {
+
+ AttributeLayoutMap attributeDefinitionMap = segment.getAttrDefinitionBands().getAttributeDefinitionMap();
+ int classCount = header.getClassCount();
+ long[][] methodFlags = segment.getClassBands().getMethodFlags();
+ int[] codeMaxNALocals = segment.getClassBands().getCodeMaxNALocals();
+ int[] codeMaxStack = segment.getClassBands().getCodeMaxStack();
+ ArrayList[][] methodAttributes = segment.getClassBands().getMethodAttributes();
+ String[][] methodDescr = segment.getClassBands().getMethodDescr();
+
+ int bcStringRefCount = 0;
+ int bcInitRefCount = 0;
+ int bcFieldRefCount = 0;
+ int bcThisFieldCount = 0;
+ int bcMethodRefCount = 0;
+ int bcIMethodRefCount = 0;
+
+ AttributeLayout abstractModifier = attributeDefinitionMap
+ .getAttributeLayout(AttributeLayout.ACC_ABSTRACT,
+ AttributeLayout.CONTEXT_METHOD);
+ AttributeLayout nativeModifier = attributeDefinitionMap
+ .getAttributeLayout(AttributeLayout.ACC_NATIVE,
+ AttributeLayout.CONTEXT_METHOD);
+ AttributeLayout staticModifier = attributeDefinitionMap
+ .getAttributeLayout(AttributeLayout.ACC_STATIC,
+ AttributeLayout.CONTEXT_METHOD);
+ methodByteCodePacked = new byte[classCount][][];
+ int bcParsed = 0;
+ for (int c = 0; c < classCount; c++) {
+ int numberOfMethods = methodFlags[c].length;
+ methodByteCodePacked[c] = new byte[numberOfMethods][];
+ for (int m = 0; m < numberOfMethods; m++) {
+ long methodFlag = methodFlags[c][m];
+ if (!abstractModifier.matches(methodFlag)
+ && !nativeModifier.matches(methodFlag)) {
+ ByteArrayOutputStream codeBytes = new ByteArrayOutputStream();
+ byte code;
+ while ((code = (byte) (0xff & in.read())) != -1)
+ codeBytes.write(code);
+ methodByteCodePacked[c][m] = codeBytes.toByteArray();
+ bcParsed += methodByteCodePacked[c][m].length;
+ for (int i = 0; i < methodByteCodePacked[c][m].length; i++) {
+ int codePacked = 0xff & methodByteCodePacked[c][m][i];
+ // TODO a lot of this needs to be encapsulated in the
+ // place that
+ // calculates what the arguments are, since (a) it will
+ // need
+ // to know where to get them, and (b) what to do with
+ // them
+ // once they've been gotten. But that's for another
+ // time.
+ switch (codePacked) {
+ case 18: // (a)ldc
+ bcStringRefCount++;
+ break;
+ case 178: // getstatic
+ case 179: // putstatic
+ case 180: // getfield
+ case 181: // putfield
+ bcFieldRefCount++;
+ break;
+ case 182: // invokevirtual
+ case 183: // invokespecial
+ case 184: // invokestatic
+ bcMethodRefCount++;
+ break;
+ case 185: // invokeinterface
+ bcIMethodRefCount++;
+ break;
+ case 202: // getstatic_this
+ case 203: // putstatic_this
+ case 204: // getfield_this
+ case 205: // putfield_this
+ bcThisFieldCount++;
+ break;
+ case 231: // invoke_special_init
+ bcInitRefCount++;
+ break;
+
+ default: // unhandled specifically at this stage
+ debug("Found unhandled "
+ + ByteCode.getByteCode(codePacked));
+ }
+ }
+ }
+ }
+ }
+ // other bytecode bands
+ debug("Parsed *bc_codes (" + bcParsed + ")");
+ debug("unimplemented bc_case_count");
+ debug("unimplemented bc_case_value");
+ debug("unimplemented bc_byte");
+ debug("unimplemented bc_short");
+ debug("unimplemented bc_local");
+ debug("unimplemented bc_label");
+ debug("unimplemented bc_intref");
+ debug("unimplemented bc_floatref");
+ debug("unimplemented bc_longref");
+ debug("unimplemented bc_doubleref");
+ int[] bcStringRef = decodeBandInt("bc_stringref", in, Codec.DELTA5,
+ bcStringRefCount);
+ debug("unimplemented bc_classref");
+ int[] bcFieldRef = decodeBandInt("bc_fieldref", in, Codec.DELTA5,
+ bcFieldRefCount);
+ int[] bcMethodRef = decodeBandInt("bc_methodref", in, Codec.UNSIGNED5,
+ bcMethodRefCount);
+ int[] bcIMethodRef = decodeBandInt("bc_imethodref", in, Codec.DELTA5,
+ bcIMethodRefCount);
+ int[] bcThisField = decodeBandInt("bc_thisfield", in, Codec.UNSIGNED5,
+ bcThisFieldCount);
+ debug("unimplemented bc_superfield");
+ debug("unimplemented bc_thismethod");
+ debug("unimplemented bc_supermethod");
+ debug("unimplemented bc_initref");
+ int[] bcInitRef = decodeBandInt("bc_initref", in, Codec.UNSIGNED5,
+ bcInitRefCount);
+ debug("unimplemented bc_escref");
+ debug("unimplemented bc_escrefsize");
+ debug("unimplemented bc_escsize");
+ debug("unimplemented bc_escbyte");
+ int i = 0;
+ for (int c = 0; c < classCount; c++) {
+ int numberOfMethods = methodFlags[c].length;
+ for (int m = 0; m < numberOfMethods; m++) {
+ long methodFlag = methodFlags[c][m];
+ if (!abstractModifier.matches(methodFlag)
+ && !nativeModifier.matches(methodFlag)) {
+ int maxStack = codeMaxStack[i];
+ int maxLocal = codeMaxNALocals[i];
+ if (!staticModifier.matches(methodFlag))
+ maxLocal++; // one for 'this' parameter
+ maxLocal += SegmentUtils.countArgs(methodDescr[c][m]);
+ // TODO Move creation of code attribute until after constant
+ // pool resolved
+ CodeAttribute attr = new CodeAttribute(maxStack, maxLocal,
+ methodByteCodePacked[c][m]);
+ methodAttributes[c][m].add(attr);
+ i++;
+ }
+ }
+ }
+
+ }
+
+}
Index: src/main/java/org/apache/harmony/pack200/ClassBands.java
===================================================================
--- src/main/java/org/apache/harmony/pack200/ClassBands.java
+++ src/main/java/org/apache/harmony/pack200/ClassBands.java
@@ -0,0 +1,523 @@
+/*
+ * 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;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+
+import org.apache.harmony.pack200.bytecode.CPClass;
+import org.apache.harmony.pack200.bytecode.ConstantValueAttribute;
+import org.apache.harmony.pack200.bytecode.ExceptionsAttribute;
+
+/**
+ *
+ */
+public class ClassBands extends BandSet {
+
+ private int classAttrCount;
+
+ private int[] classFieldCount;
+
+ private long[] classFlags;
+
+ private String[][] classInterfaces;
+
+ private int[] classMethodCount;
+
+ private String[] classSuper;
+
+ private String[] classThis;
+
+ private int[] codeHandlerCount;
+
+ private int[] codeMaxNALocals;
+
+ private int[] codeMaxStack;
+
+ private int fieldAttrCount;
+
+ private ArrayList[][] fieldAttributes;
+
+ private String[][] fieldDescr;
+
+ private long[][] fieldFlags;
+
+ private int methodAttrCount;
+
+ private ArrayList[][] methodAttributes;
+
+ private String[][] methodDescr;
+
+ private ExceptionsAttribute[][] methodExceptions;
+
+ private long[][] methodFlags;
+
+ private AttributeLayoutMap attrMap;
+
+ private CpBands cpBands;
+
+ /**
+ * @param header
+ */
+ public ClassBands(Segment segment){
+ super(segment);
+ this.attrMap = segment.getAttrDefinitionBands().getAttributeDefinitionMap();
+ this.cpBands = segment.getCpBands();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.apache.harmony.pack200.BandSet#pack(java.io.OutputStream)
+ */
+ public void pack(OutputStream outputStream) {
+ // TODO Auto-generated method stub
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.apache.harmony.pack200.BandSet#unpack(java.io.InputStream)
+ */
+ public void unpack(InputStream in) throws IOException,
+ Pack200Exception {
+ int classCount = header.getClassCount();
+ classThis = parseReferences("class_this", in, Codec.DELTA5, classCount,
+ 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,
+ classCount, classInterfaceLengths, cpBands.getCpClass());
+ // }
+ 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 parseFieldBands(InputStream in) throws IOException,
+ Pack200Exception {
+ int classCount = header.getClassCount();
+ SegmentOptions options = header.getOptions();
+ fieldDescr = parseReferences("field_descr", in, Codec.DELTA5,
+ classCount, classFieldCount, cpBands.getCpDescriptor());
+ fieldFlags = parseFlags("field_flags", in, classCount, classFieldCount,
+ 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");
+ 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");
+ }
+ }
+ }
+ debug("unimplemented field_Signature_RS");
+ parseMetadataBands(AttributeLayout.CONTEXT_FIELD);
+ }
+
+ private void parseMethodBands(InputStream in) throws IOException,
+ Pack200Exception {
+ int classCount = header.getClassCount();
+ SegmentOptions options = header.getOptions();
+ methodDescr = parseReferences("method_descr", in, Codec.MDELTA5,
+ classCount, classMethodCount, cpBands.getCpDescriptor());
+ methodFlags = parseFlags("method_flags", in, classCount,
+ 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];
+ 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");
+ // assign empty method attributes
+ methodAttributes = new ArrayList[classCount][];
+ for (int i = 0; i < classCount; i++) {
+ methodAttributes[i] = new ArrayList[methodFlags[i].length];
+ for (int j = 0; j < methodFlags[i].length; j++) {
+ methodAttributes[i][j] = new ArrayList();
+ }
+ }
+ parseAttributeMethodExceptions(in);
+ parseAttributeMethodSignature(in);
+ parseMetadataBands(AttributeLayout.CONTEXT_METHOD);
+ }
+
+ /**
+ * @param in
+ * @throws Pack200Exception
+ * @throws IOException
+ */
+ 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);
+ }
+ }
+ }
+ for (int i = 0; i < classCount; i++) {
+ 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]);
+ }
+ }
+ methodExceptions[i][j] = new ExceptionsAttribute(exceptions);
+ methodAttributes[i][j].add(methodExceptions[i][j]);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * @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++) {
+ 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");
+ AttributeLayout layout = attrMap.getAttributeLayout(
+ AttributeLayout.ATTRIBUTE_SOURCE_FILE,
+ AttributeLayout.CONTEXT_CLASS);
+ for (int i = 0; i < classCount; i++) {
+ long flag = classFlags[i];
+ if (layout.matches(flag)) {
+ // 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.getConstantPool());
+ debug("Processed value " + value + " for SourceFile");
+ }
+ }
+ debug("unimplemented class_EnclosingMethod_RC");
+ debug("unimplemented class_EnclosingMethod_RDN");
+ debug("unimplemented class_Signature_RS");
+ parseMetadataBands(AttributeLayout.CONTEXT_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 parseCodeBands(InputStream in) throws Pack200Exception,
+ IOException {
+ AttributeLayout layout = attrMap.getAttributeLayout(
+ AttributeLayout.ATTRIBUTE_CODE, AttributeLayout.CONTEXT_METHOD);
+
+ int codeBands = SegmentUtils.countMatches(methodFlags, layout);
+ int[] codeHeaders = decodeBandInt("code_headers", in, Codec.BYTE1,
+ codeBands);
+ int codeSpecialHeader = 0;
+ for (int i = 0; i < codeBands; i++) {
+ if (codeHeaders[i] == 0)
+ codeSpecialHeader++;
+ }
+ int[] codeMaxStackSpecials = decodeBandInt("code_max_stack", in,
+ Codec.UNSIGNED5, codeSpecialHeader);
+ int[] codeMaxNALocalsSpecials = decodeBandInt("code_max_na_locals", in,
+ Codec.UNSIGNED5, codeSpecialHeader);
+ int[] codeHandlerCountSpecials = decodeBandInt("code_handler_count",
+ in, Codec.UNSIGNED5, codeSpecialHeader);
+
+ codeMaxStack = new int[codeBands];
+ codeMaxNALocals = new int[codeBands];
+ codeHandlerCount = new int[codeBands];
+ int special = 0;
+ for (int i = 0; i < codeBands; i++) {
+ int header = 0xff & codeHeaders[i];
+ if (header < 0) {
+ throw new IllegalStateException("Shouldn't get here");
+ } else if (header == 0) {
+ codeMaxStack[i] = codeMaxStackSpecials[special];
+ codeMaxNALocals[i] = codeMaxNALocalsSpecials[special];
+ codeHandlerCount[i] = codeHandlerCountSpecials[special];
+ special++;
+ } else if (header <= 144) {
+ codeMaxStack[i] = (header - 1) % 12;
+ codeMaxNALocals[i] = (header - 1) / 12;
+ codeHandlerCount[i] = 0;
+ } else if (header <= 208) {
+ codeMaxStack[i] = (header - 145) % 8;
+ codeMaxNALocals[i] = (header - 145) / 8;
+ codeHandlerCount[i] = 1;
+ } else if (header <= 255) {
+ codeMaxStack[i] = (header - 209) % 7;
+ codeMaxNALocals[i] = (header - 209) / 7;
+ codeHandlerCount[i] = 2;
+ } else {
+ throw new IllegalStateException("Shouldn't get here either");
+ }
+ }
+ 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 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");
+ }
+ }
+
+ private void parseMetadataBands(int context) throws Pack200Exception {
+ String[] RxA;
+ if (AttributeLayout.CONTEXT_METHOD == context) {
+ RxA = new String[] { "RVA", "RIA", "RVPA", "RIPA", "AD" };
+ } else if (AttributeLayout.CONTEXT_FIELD == context
+ || AttributeLayout.CONTEXT_CLASS == context) {
+ RxA = new String[] { "RVA", "RIA" };
+ } else {
+ throw new Pack200Exception("Unknown type of metadata unit "
+ + context);
+ }
+ // AttributeLayout layout =
+ // map.get(RuntimeVisibleAnnotations,class/field/method as int)
+ // foreachheader ...
+ // if layout.matches(header[n] or whatever)
+ String contextName = (AttributeLayout.CONTEXT_METHOD == context ? "method"
+ : (AttributeLayout.CONTEXT_FIELD == context ? "field"
+ : (AttributeLayout.CONTEXT_CLASS == context ? "class"
+ : "unkowon")));
+ for (int i = 0; i < RxA.length; i++) {
+ String rxa = RxA[i];
+ if (rxa.indexOf("P") >= 0) {
+ debug("unimplemented " + contextName + "_" + rxa + "_param_NB");
+ }
+ if (!rxa.equals("AD")) {
+ debug("unimplemented " + contextName + "_" + rxa + "_anno_N");
+ debug("unimplemented " + contextName + "_" + rxa + "_type_RS");
+ debug("unimplemented " + contextName + "_" + rxa + "_pair_N");
+ debug("unimplemented " + contextName + "_" + rxa + "_name_RU");
+ }
+ debug("unimplemented " + contextName + "_" + rxa + "_T");
+ debug("unimplemented " + contextName + "_" + rxa + "_caseI_KI");
+ debug("unimplemented " + contextName + "_" + rxa + "_caseD_KD");
+ debug("unimplemented " + contextName + "_" + rxa + "_caseF_KF");
+ debug("unimplemented " + contextName + "_" + rxa + "_caseJ_KJ");
+ debug("unimplemented " + contextName + "_" + rxa + "_casec_RS");
+ debug("unimplemented " + contextName + "_" + rxa + "_caseet_RS");
+ debug("unimplemented " + contextName + "_" + rxa + "_caseec_RU");
+ debug("unimplemented " + contextName + "_" + rxa + "_cases_RU");
+ debug("unimplemented " + contextName + "_" + rxa + "_casearray_N");
+ debug("unimplemented " + contextName + "_" + rxa + "_nesttype_RS");
+ debug("unimplemented " + contextName + "_" + rxa + "_nestpair_N");
+ debug("unimplemented " + contextName + "_" + rxa + "_nestname_RU");
+ }
+ }
+
+ public int getClassAttrCount() {
+ return classAttrCount;
+ }
+
+ public int[] getClassFieldCount() {
+ return classFieldCount;
+ }
+
+ public long[] getClassFlags() {
+ return classFlags;
+ }
+
+ public String[][] getClassInterfaces() {
+ return classInterfaces;
+ }
+
+ public int[] getClassMethodCount() {
+ return classMethodCount;
+ }
+
+ public String[] getClassSuper() {
+ return classSuper;
+ }
+
+ public String[] getClassThis() {
+ return classThis;
+ }
+
+ public int[] getCodeMaxNALocals() {
+ return codeMaxNALocals;
+ }
+
+ public int[] getCodeMaxStack() {
+ return codeMaxStack;
+ }
+
+ public int getFieldAttrCount() {
+ return fieldAttrCount;
+ }
+
+ public ArrayList[][] getFieldAttributes() {
+ return fieldAttributes;
+ }
+
+ public String[][] getFieldDescr() {
+ return fieldDescr;
+ }
+
+ public long[][] getFieldFlags() {
+ return fieldFlags;
+ }
+
+ public int getMethodAttrCount() {
+ return methodAttrCount;
+ }
+
+ public ArrayList[][] getMethodAttributes() {
+ return methodAttributes;
+ }
+
+ public String[][] getMethodDescr() {
+ return methodDescr;
+ }
+
+ public ExceptionsAttribute[][] getMethodExceptions() {
+ return methodExceptions;
+ }
+
+ public long[][] getMethodFlags() {
+ return methodFlags;
+ }
+
+}
Index: src/main/java/org/apache/harmony/pack200/CpBands.java
===================================================================
--- src/main/java/org/apache/harmony/pack200/CpBands.java
+++ src/main/java/org/apache/harmony/pack200/CpBands.java
@@ -0,0 +1,439 @@
+/*
+ * 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;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+
+public class CpBands extends BandSet {
+
+ public SegmentConstantPool getConstantPool() {
+ return pool;
+ }
+
+
+ private final SegmentConstantPool pool = new SegmentConstantPool(this);
+
+ private String[] cpClass;
+
+ private String[] cpDescriptor;
+
+ private double[] cpDouble;
+
+ private String[] cpFieldClass;
+
+ private Object cpFieldDescriptor;
+
+ private float[] cpFloat;
+
+ private String[] cpIMethodClass;
+
+ private String[] cpIMethodDescriptor;
+
+ private int[] cpInt;
+
+ private long[] cpLong;
+
+ private String[] cpMethodClass;
+
+ private String[] cpMethodDescriptor;
+
+ private String[] cpSignature;
+
+ private String[] cpString;
+
+ private String[] cpUTF8;
+
+
+ public CpBands(Segment segment) {
+ super(segment);
+ }
+
+ public void unpack(InputStream in) throws IOException, Pack200Exception {
+ parseCpUtf8(in);
+ parseCpInt(in);
+ parseCpFloat(in);
+ parseCpLong(in);
+ parseCpDouble(in);
+ parseCpString(in);
+ parseCpClass(in);
+ parseCpSignature(in);
+ parseCpDescriptor(in);
+ parseCpField(in);
+ parseCpMethod(in);
+ parseCpIMethod(in);
+ }
+
+ public void pack(OutputStream outputStream) {
+
+ }
+
+ /**
+ * Parses the constant pool class names, using {@link #cpClassCount} to
+ * populate {@link #cpClass} from {@link #cpUTF8}.
+ *
+ * @param in
+ * the input stream to read from
+ * @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 void parseCpClass(InputStream in) throws IOException,
+ Pack200Exception {
+ int cpClassCount = header.getCpClassCount();
+ cpClass = parseReferences("cp_Class", in, Codec.UDELTA5, cpClassCount,
+ cpUTF8);
+ }
+
+
+ /**
+ * Parses the constant pool descriptor definitions, using
+ * {@link #cpDescriptorCount} to populate {@link #cpDescriptor}. For ease
+ * of use, the cpDescriptor is stored as a string of the form name:type,
+ * largely to make it easier for representing field and method descriptors
+ * (e.g. out:java.lang.PrintStream) in a way that is
+ * compatible with passing String arrays.
+ *
+ * @param in
+ * the input stream to read from
+ * @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 void parseCpDescriptor(InputStream in) throws IOException,
+ Pack200Exception {
+ int cpDescriptorCount = header.getCpDescriptorCount();
+ 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]; //$NON-NLS-1$
+ }
+ }
+
+ private void parseCpDouble(InputStream in) throws IOException,
+ Pack200Exception {
+ int cpDoubleCount = header.getCpDoubleCount();
+ cpDouble = new double[cpDoubleCount];
+ 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++) {
+ cpDouble[i] = Double.longBitsToDouble(hiBits[i] << 32 | loBits[i]);
+ }
+ }
+
+ /**
+ * Parses the constant pool field definitions, using {@link #cpFieldCount}
+ * to populate {@link #cpFieldClass} and {@link #cpFieldDescriptor}.
+ *
+ * @param in
+ * the input stream to read from
+ * @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 void parseCpField(InputStream in) throws IOException,
+ Pack200Exception {
+ int cpFieldCount = header.getCpFieldCount();
+ 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 {
+ int cpFloatCount = header.getCpFloatCount();
+ cpFloat = new float[cpFloatCount];
+ int floatBits[] = decodeBandInt("cp_Float", in, Codec.UDELTA5,
+ cpFloatCount);
+ for (int i = 0; i < cpFloatCount; i++) {
+ cpFloat[i] = Float.intBitsToFloat(floatBits[i]);
+ }
+ }
+
+ /**
+ * Parses the constant pool interface method definitions, using
+ * {@link #cpIMethodCount} to populate {@link #cpIMethodClass} and
+ * {@link #cpIMethodDescriptor}.
+ *
+ * @param in
+ * the input stream to read from
+ * @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 void parseCpIMethod(InputStream in) throws IOException,
+ Pack200Exception {
+ int cpIMethodCount = header.getCpIMethodCount();
+ 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,
+ Pack200Exception {
+ int cpIntCount = header.getCpIntCount();
+ cpInt = new int[cpIntCount];
+ long last = 0;
+ for (int i = 0; i < cpIntCount; i++) {
+ last = Codec.UDELTA5.decode(in, last);
+ cpInt[i] = (int) last;
+ }
+ }
+
+ 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];
+ }
+
+ /**
+ * Parses the constant pool method definitions, using {@link #cpMethodCount}
+ * to populate {@link #cpMethodClass} and {@link #cpMethodDescriptor}.
+ *
+ * @param in
+ * the input stream to read from
+ * @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 void parseCpMethod(InputStream in) throws IOException,
+ Pack200Exception {
+ int cpMethodCount = header.getCpMethodCount();
+ cpMethodClass = parseReferences("cp_Method_class", in, Codec.DELTA5,
+ cpMethodCount, cpClass);
+ cpMethodDescriptor = parseReferences("cp_Method_desc", in,
+ Codec.UDELTA5, cpMethodCount, cpDescriptor);
+ }
+
+ /**
+ * Parses the constant pool signature classes, using
+ * {@link #cpSignatureCount} to populate {@link #cpSignature}. A signature
+ * form is akin to the bytecode representation of a class; Z for boolean, I
+ * for int, [ for array etc. However, although classes are started with L,
+ * the classname does not follow the form; instead, there is a separate
+ * array of classes. So an array corresponding to
+ * public static void main(String args[]) has a form of
+ * [L(V) and a classes array of
+ * [java.lang.String]. The {@link #cpSignature} is a string
+ * representation identical to the bytecode equivalent
+ * [Ljava/lang/String;(V) TODO Check that the form is as
+ * above and update other types e.g. J
+ *
+ * @param in
+ * the input stream to read from
+ * @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 void parseCpSignature(InputStream in) throws IOException,
+ Pack200Exception {
+ int cpSignatureCount = header.getCpSignatureCount();
+ 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++) {
+ String form = cpSignatureForm[i];
+ int len = form.length();
+ StringBuffer signature = new StringBuffer(64);
+ ArrayList list = new ArrayList();
+ for (int j = 0; j < len; j++) {
+ char c = form.charAt(j);
+ signature.append(c);
+ if (c == 'L') {
+ int index = (int) (last = Codec.UDELTA5.decode(in, last));
+ String className = cpClass[index];
+ list.add(className);
+ signature.append(className);
+ }
+ }
+ cpSignature[i] = signature.toString();
+ }
+ }
+
+ /**
+ * Parses the constant pool strings, using {@link #cpStringCount} to
+ * populate {@link #cpString} from indexes into {@link #cpUTF8}.
+ *
+ * @param in
+ * the input stream to read from
+ * @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 void parseCpString(InputStream in) throws IOException,
+ Pack200Exception {
+ int cpStringCount = header.getCpStringCount();
+ cpString = new String[cpStringCount];
+ long last = 0;
+ for (int i = 0; i < cpStringCount; i++) {
+ int index = (int) (last = Codec.UDELTA5.decode(in, last));
+ cpString[i] = cpUTF8[index];
+ }
+ }
+
+ private void parseCpUtf8(InputStream in) throws IOException,
+ Pack200Exception {
+ int cpUTF8Count = header.getCpUTF8Count();
+ // TODO Update codec.decode -> decodeScalar
+ cpUTF8 = new String[cpUTF8Count];
+ cpUTF8[0] = ""; //$NON-NLS-1$
+ int[] prefix = new int[cpUTF8Count];
+ int[] suffix = new int[cpUTF8Count];
+ if (cpUTF8Count > 0) {
+ prefix[0] = 0;
+ suffix[0] = 0;
+ if (cpUTF8Count > 1)
+ prefix[1] = 0;
+ }
+ long last = 0;
+ for (int i = 2; i < cpUTF8Count; i++) {
+ last = prefix[i] = (int) Codec.DELTA5.decode(in, last);
+ }
+ int chars = 0;
+ int bigSuffix = 0;
+ for (int i = 1; i < cpUTF8Count; i++) {
+ last = suffix[i] = (int) Codec.UNSIGNED5.decode(in);
+ if (last == 0) {
+ bigSuffix++;
+ } else {
+ chars += last;
+ }
+ }
+ char data[] = new char[chars];
+ for (int i = 0; i < data.length; i++) {
+ data[i] = (char) Codec.CHAR3.decode(in);
+ }
+ // read in the big suffix data
+ char bigSuffixData[][] = new char[bigSuffix][];
+ last = 0;
+ for (int i = 0; i < bigSuffix; i++) {
+ last = (int) Codec.DELTA5.decode(in, last);
+ bigSuffixData[i] = new char[(int) last];
+ }
+ // initialize big suffix data
+ for (int i = 0; i < bigSuffix; i++) {
+ char[] singleBigSuffixData = bigSuffixData[i];
+ last = 0;
+ for (int j = 0; j < singleBigSuffixData.length; j++) {
+ last = singleBigSuffixData[j] = (char) Codec.DELTA5.decode(in,
+ last);
+ }
+ }
+ // go through the strings
+ chars = 0;
+ bigSuffix = 0;
+ for (int i = 1; i < cpUTF8Count; i++) {
+ String lastString = cpUTF8[i - 1];
+ if (suffix[i] == 0) {
+ // The big suffix stuff hasn't been tested, and I'll be
+ // surprised if it works first time w/o errors ...
+ cpUTF8[i] = lastString.substring(0, prefix[i])
+ + new String(bigSuffixData[bigSuffix++]);
+ } else {
+ cpUTF8[i] = lastString.substring(0, prefix[i])
+ + new String(data, chars, suffix[i]);
+ chars += suffix[i];
+ }
+ }
+ }
+
+ public String[] getCpClass() {
+ return cpClass;
+ }
+
+ public String[] getCpDescriptor() {
+ return cpDescriptor;
+ }
+
+ public double[] getCpDouble() {
+ return cpDouble;
+ }
+
+ public String[] getCpFieldClass() {
+ return cpFieldClass;
+ }
+
+ public Object getCpFieldDescriptor() {
+ return cpFieldDescriptor;
+ }
+
+ public float[] getCpFloat() {
+ return cpFloat;
+ }
+
+ public String[] getCpIMethodClass() {
+ return cpIMethodClass;
+ }
+
+ public String[] getCpIMethodDescriptor() {
+ return cpIMethodDescriptor;
+ }
+
+ public int[] getCpInt() {
+ return cpInt;
+ }
+
+ public long[] getCpLong() {
+ return cpLong;
+ }
+
+ public String[] getCpMethodClass() {
+ return cpMethodClass;
+ }
+
+ public String[] getCpMethodDescriptor() {
+ return cpMethodDescriptor;
+ }
+
+ public String[] getCpSignature() {
+ return cpSignature;
+ }
+
+ public String[] getCpString() {
+ return cpString;
+ }
+
+ public String[] getCpUTF8() {
+ return cpUTF8;
+ }
+
+}
Index: src/main/java/org/apache/harmony/pack200/FileBands.java
===================================================================
--- src/main/java/org/apache/harmony/pack200/FileBands.java
+++ src/main/java/org/apache/harmony/pack200/FileBands.java
@@ -0,0 +1,147 @@
+/*
+ * 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;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+
+/**
+ * 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
+ * start of the file_bits themselves, and there will be Sum(file_size) bits
+ * remaining in the stream with BYTE1 compression. A decent implementation
+ * will probably just stream the bytes out to the reconstituted Jar rather
+ * than caching them.
+ *
+ */
+public class FileBands extends BandSet {
+
+ private byte[][] fileBits;
+
+ private long[] fileModtime;
+
+ private String[] fileName;
+
+ private long[] fileOptions;
+
+ private long[] fileSize;
+
+ private String[] cpUTF8;
+
+ /**
+ * @param header
+ */
+ public FileBands(Segment segment) {
+ super(segment);
+ this.cpUTF8 = segment.getCpBands().getCpUTF8();
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.harmony.pack200.BandSet#pack(java.io.OutputStream)
+ */
+ public void pack(OutputStream outputStream) {
+ // TODO Auto-generated method stub
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.harmony.pack200.BandSet#unpack(java.io.InputStream)
+ */
+ public void unpack(InputStream in) throws IOException,
+ 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];
+ if (options.hasFileModtime()) {
+ last = 0;
+ for (int i = 0; i < numberOfFiles; i++) {
+ fileModtime[i] |= (last = Codec.DELTA5.decode(in, last));
+ }
+ }
+ fileOptions = new long[numberOfFiles];
+ if (options.hasFileOptions()) {
+ last = 0;
+ for (int i = 0; i < numberOfFiles; i++) {
+ fileOptions[i] |= (last = Codec.UNSIGNED5.decode(in, last));
+ }
+ }
+ }
+
+
+ public void processFileBits(InputStream in) throws IOException,
+ Pack200Exception {
+ // now read in the bytes
+ int numberOfFiles = header.getNumberOfFiles();
+ fileBits = new byte[numberOfFiles][];
+ for (int i = 0; i < numberOfFiles; i++) {
+ int size = (int) fileSize[i];
+ // TODO This buggers up if file_size > 2^32. Probably an array is
+ // not the right choice, and
+ // we should just serialize the bugger here?
+ fileBits[i] = new byte[size];
+ for (int j = 0; j < size; j++) {
+ fileBits[i][j] = (byte) Codec.BYTE1.decode(in);
+ }
+ }
+ }
+
+ public byte[][] getFileBits() {
+ return fileBits;
+ }
+
+ public long[] getFileModtime() {
+ return fileModtime;
+ }
+
+ public String[] getFileName() {
+ return fileName;
+ }
+
+ public long[] getFileOptions() {
+ return fileOptions;
+ }
+
+ public long[] getFileSize() {
+ return fileSize;
+ }
+
+}
Index: src/main/java/org/apache/harmony/pack200/IcBands.java
===================================================================
--- src/main/java/org/apache/harmony/pack200/IcBands.java
+++ src/main/java/org/apache/harmony/pack200/IcBands.java
@@ -0,0 +1,80 @@
+/*
+ * 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;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ *
+ */
+public class IcBands extends BandSet {
+
+ private int[] icFlags;
+
+ private Object icName;
+
+ private String[] icOuterClass;
+
+ private String[] icThisClass;
+
+ private String[] cpUTF8;
+
+ private String[] cpClass;
+
+ /**
+ * @param header
+ */
+ public IcBands(Segment segment) {
+ super(segment);
+ this.cpClass = segment.getCpBands().getCpClass();
+ this.cpUTF8 = segment.getCpBands().getCpUTF8();
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.harmony.pack200.BandSet#pack(java.io.OutputStream)
+ */
+ public void pack(OutputStream outputStream) {
+ // TODO Auto-generated method stub
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.harmony.pack200.BandSet#unpack(java.io.InputStream)
+ */
+ public void unpack(InputStream in) throws IOException,
+ Pack200Exception {
+ int innerClassCount = header.getInnerClassCount();
+ 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("ic_outer_class", in, Codec.DELTA5,
+ outerClasses, cpClass);
+ icName = parseReferences("ic_name", in, Codec.DELTA5, outerClasses,
+ cpUTF8);
+ }
+
+}
Index: src/main/java/org/apache/harmony/pack200/SegmentConstantPool.java
===================================================================
--- src/main/java/org/apache/harmony/pack200/SegmentConstantPool.java
+++ src/main/java/org/apache/harmony/pack200/SegmentConstantPool.java
@@ -0,0 +1,75 @@
+/*
+ * 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;
+
+public class SegmentConstantPool {
+ /**
+ *
+ */
+ private CpBands bands;
+
+ /**
+ * @param bands
+ */
+ public SegmentConstantPool(CpBands bands) {
+ this.bands = bands;
+ }
+
+ public static final int ALL = 0;
+
+ public static final int CP_DOUBLE = 7;
+
+ // define in archive order
+
+ public static final int CP_FLOAT = 4; // TODO Check this
+
+ public static final int CP_INT = 3;
+
+ public static final int CP_LONG = 6;
+
+ public static final int CP_STRING = 5;
+
+ public static final int SIGNATURE = 2; // TODO and more to come --
+
+ public static final int UTF_8 = 1;
+
+ public Object getValue(int cp, long value) throws Pack200Exception {
+ int index = (int) value;
+ if (index == -1) {
+ return null;
+ } else if (index < 0) {
+ throw new Pack200Exception("Cannot have a negative range");
+ } else if (cp == UTF_8) {
+ return bands.getCpUTF8()[index];
+ } else if (cp == CP_STRING) {
+ return bands.getCpString()[index];
+ } else if (cp == SIGNATURE) {
+ return bands.getCpSignature()[index];
+ } else if (cp == CP_INT) {
+ return new Integer(bands.getCpInt()[index]);
+ } else if (cp == CP_FLOAT) {
+ return new Float(bands.getCpFloat()[index]);
+ } else if (cp == CP_DOUBLE) {
+ return new Double(bands.getCpDouble()[index]);
+ } else if (cp == CP_LONG) {
+ return new Long(bands.getCpLong()[index]);
+ } else {
+ // etc
+ throw new Error("Get value incomplete");
+ }
+ }
+}
\ No newline at end of file
Index: src/main/java/org/apache/harmony/pack200/SegmentHeader.java
===================================================================
--- src/main/java/org/apache/harmony/pack200/SegmentHeader.java
+++ src/main/java/org/apache/harmony/pack200/SegmentHeader.java
@@ -0,0 +1,415 @@
+/*
+ * 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;
+
+import java.io.ByteArrayInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class SegmentHeader {
+
+ private int archiveMajor;
+
+ private int archiveMinor;
+
+ private long archiveModtime;
+
+ private long archiveSize;
+
+ private int attributeDefinitionCount;
+
+ private InputStream bandHeadersInputStream;
+
+ private int bandHeadersSize;
+
+ private int classCount;
+
+ private int cpClassCount;
+
+ private int cpDescriptorCount;
+
+ private int cpDoubleCount;
+
+ private int cpFieldCount;
+
+ private int cpFloatCount;
+
+ private int cpIMethodCount;
+
+ private int cpIntCount;
+
+ private int cpLongCount;
+
+ private int cpMethodCount;
+
+ private int cpSignatureCount;
+
+ private int cpStringCount;
+
+ private int cpUTF8Count;
+
+ private int defaultClassMajorVersion;
+
+ private int defaultClassMinorVersion;
+
+ private int innerClassCount;
+
+ private int numberOfFiles;
+
+ private int segmentsRemaining;
+
+ private SegmentOptions options;
+
+
+ /**
+ * The magic header for a Pack200 Segment is 0xCAFED00D. I wonder where they
+ * get their inspiration from ...
+ */
+ private static final int[] magic = { 0xCA, 0xFE, 0xD0, 0x0D };
+
+ public void unpack(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 (word[m] != magic[m])
+ throw new Error("Bad header");
+ setArchiveMinorVersion((int) decodeScalar("archive_minver", in,
+ Codec.UNSIGNED5));
+ setArchiveMajorVersion((int) decodeScalar("archive_majver", in,
+ Codec.UNSIGNED5));
+ options = new SegmentOptions((int) decodeScalar("archive_options", in,
+ Codec.UNSIGNED5));
+ parseArchiveFileCounts(in);
+ parseArchiveSpecialCounts(in);
+ parseCpCounts(in);
+ parseClassCounts(in);
+
+ if (getBandHeadersSize() > 0) {
+ byte[] bandHeaders = new byte[(int) getBandHeadersSize()];
+ readFully(in, bandHeaders);
+ setBandHeadersData(bandHeaders);
+ }
+ }
+
+ /**
+ * Sets the minor version of this archive
+ *
+ * @param version
+ * the minor version of the archive
+ * @throws Pack200Exception
+ * if the minor version is not 7
+ */
+ private void setArchiveMinorVersion(int version) throws Pack200Exception {
+ if (version != 7)
+ throw new Pack200Exception("Invalid segment minor version");
+ archiveMinor = version;
+ }
+
+ /**
+ * Sets the major version of this archive.
+ *
+ * @param version
+ * the minor version of the archive
+ * @throws Pack200Exception
+ * if the major version is not 150
+ */
+ private void setArchiveMajorVersion(int version) throws Pack200Exception {
+ if (version != 150)
+ throw new Pack200Exception("Invalid segment major version");
+ archiveMajor = version;
+ }
+
+ public long getArchiveModtime() {
+ return archiveModtime;
+ }
+
+ public int getArchiveMajor() {
+ return archiveMajor;
+ }
+
+ public int getArchiveMinor() {
+ return archiveMinor;
+ }
+
+ public int getAttributeDefinitionCount() {
+ return attributeDefinitionCount;
+ }
+
+ public int getClassCount() {
+ return classCount;
+ }
+
+ public int getCpClassCount() {
+ return cpClassCount;
+ }
+
+ public int getCpDescriptorCount() {
+ return cpDescriptorCount;
+ }
+
+ public int getCpDoubleCount() {
+ return cpDoubleCount;
+ }
+
+ public int getCpFieldCount() {
+ return cpFieldCount;
+ }
+
+ public int getCpFloatCount() {
+ return cpFloatCount;
+ }
+
+ public int getCpIMethodCount() {
+ return cpIMethodCount;
+ }
+
+ public int getCpIntCount() {
+ return cpIntCount;
+ }
+
+ public int getCpLongCount() {
+ return cpLongCount;
+ }
+
+ public int getCpMethodCount() {
+ return cpMethodCount;
+ }
+
+ public int getCpSignatureCount() {
+ return cpSignatureCount;
+ }
+
+ public int getCpStringCount() {
+ return cpStringCount;
+ }
+
+ public int getCpUTF8Count() {
+ return cpUTF8Count;
+ }
+
+ public int getDefaultClassMajorVersion() {
+ return defaultClassMajorVersion;
+ }
+
+ public int getDefaultClassMinorVersion() {
+ return defaultClassMinorVersion;
+ }
+
+ public int getInnerClassCount() {
+ return innerClassCount;
+ }
+
+ public void setNumberOfFiles(int numberOfFiles) {
+ this.numberOfFiles = numberOfFiles;
+ }
+
+ public long getArchiveSize() {
+ 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;
+ }
+
+ public int getSegmentsRemaining() {
+ return segmentsRemaining;
+ }
+
+ public SegmentOptions getOptions() {
+ return options;
+ }
+
+ private void parseArchiveFileCounts(InputStream in) throws IOException,
+ Pack200Exception {
+ if (options.hasArchiveFileCounts()) {
+ 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));
+ numberOfFiles = (int)decodeScalar("file_count", in, Codec.UNSIGNED5);
+ }
+ }
+
+ private void parseArchiveSpecialCounts(InputStream in) throws IOException,
+ Pack200Exception {
+ if (getOptions().hasSpecialFormats()) {
+ bandHeadersSize = (int)decodeScalar("band_headers_size", in,
+ Codec.UNSIGNED5);
+ setAttributeDefinitionCount(decodeScalar("attr_definition_count",
+ in, Codec.UNSIGNED5));
+ }
+ }
+
+ private void parseClassCounts(InputStream in) throws IOException,
+ Pack200Exception {
+ innerClassCount = (int)decodeScalar("ic_count", in, Codec.UNSIGNED5);
+ defaultClassMinorVersion = (int)decodeScalar("default_class_minver", in,
+ Codec.UNSIGNED5);
+ defaultClassMajorVersion = (int)decodeScalar("default_class_majver", in,
+ Codec.UNSIGNED5);
+ classCount = (int)decodeScalar("class_count", in, Codec.UNSIGNED5);
+ }
+
+ private void parseCpCounts(InputStream in) throws IOException,
+ Pack200Exception {
+ cpUTF8Count = (int)decodeScalar("cp_Utf8_count", in, Codec.UNSIGNED5);
+ if (getOptions().hasCPNumberCounts()) {
+ cpIntCount = (int)decodeScalar("cp_Int_count", in, Codec.UNSIGNED5);
+ cpFloatCount = (int)decodeScalar("cp_Float_count", in, Codec.UNSIGNED5);
+ cpLongCount = (int)decodeScalar("cp_Long_count", in, Codec.UNSIGNED5);
+ cpDoubleCount = (int)decodeScalar("cp_Double_count", in,
+ Codec.UNSIGNED5);
+ }
+ cpStringCount = (int)decodeScalar("cp_String_count", in, Codec.UNSIGNED5);
+ cpClassCount = (int)decodeScalar("cp_Class_count", in, Codec.UNSIGNED5);
+ cpSignatureCount = (int)decodeScalar("cp_Signature_count", in,
+ Codec.UNSIGNED5);
+ cpDescriptorCount = (int)decodeScalar("cp_Descr_count", in, Codec.UNSIGNED5);
+ cpFieldCount = (int)decodeScalar("cp_Field_count", in, Codec.UNSIGNED5);
+ cpMethodCount = (int)decodeScalar("cp_Method_count", in, Codec.UNSIGNED5);
+ cpIMethodCount = (int)decodeScalar("cp_Imethod_count", in, Codec.UNSIGNED5);
+ }
+
+ /**
+ * 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);
+ }
+
+ /**
+ * 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);
+ }
+
+ public void setArchiveModtime(long archiveModtime) {
+ this.archiveModtime = archiveModtime;
+ }
+
+ public void setArchiveSize(long archiveSize) {
+ this.archiveSize = archiveSize;
+ }
+
+ private void setAttributeDefinitionCount(long valuie) {
+ this.attributeDefinitionCount = (int) valuie;
+ }
+
+ private void setBandHeadersData(byte[] bandHeaders) {
+ this.bandHeadersInputStream = new ByteArrayInputStream(bandHeaders);
+ }
+
+ public void setSegmentsRemaining(long value) {
+ segmentsRemaining = (int) value;
+ }
+
+ /**
+ * Completely reads in a byte array, akin to the implementation in
+ * {@link java.lang.DataInputStream}. TODO Refactor out into a separate
+ * InputStream handling class
+ *
+ * @param in
+ * the input stream to read from
+ * @param data
+ * the byte array to read into
+ * @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 static void readFully(InputStream in, byte[] data)
+ throws IOException, Pack200Exception {
+ int total = in.read(data);
+ if (total == -1)
+ throw new EOFException("Failed to read any data from input stream");
+ while (total < data.length) {
+ int delta = in.read(data, total, data.length - total);
+ if (delta == -1)
+ throw new EOFException(
+ "Failed to read some data from input stream");
+ total += delta;
+ }
+ }
+
+ public int getBandHeadersSize() {
+ return bandHeadersSize;
+ }
+
+
+}
Index: src/test/java/org/apache/harmony/pack200/tests/AttributeLayoutTest.java
===================================================================
--- src/test/java/org/apache/harmony/pack200/tests/AttributeLayoutTest.java (revision 565676)
+++ src/test/java/org/apache/harmony/pack200/tests/AttributeLayoutTest.java (working copy)
@@ -23,6 +23,7 @@
import org.apache.harmony.pack200.AttributeLayout;
import org.apache.harmony.pack200.Pack200Exception;
import org.apache.harmony.pack200.Segment;
+import org.apache.harmony.pack200.SegmentConstantPool;
public class AttributeLayoutTest extends TestCase {
public class TestSegment extends Segment {
@@ -32,7 +33,7 @@
{ "Zero", "One" }, // UTF-8
{ "Ein", "Zwei" }, // Signature
};
- return new SegmentConstantPool() {
+ return new SegmentConstantPool(null) {
public Object getValue(int cp, long index) {
if (index == -1)
return null;
@@ -55,9 +56,9 @@
public void testLayoutRU() throws Pack200Exception {
AttributeLayout layout = new AttributeLayout("RU",AttributeLayout.CONTEXT_CLASS,"RU", 1);
Segment segment = new TestSegment();
- assertNull(layout.getValue(-1, segment));
- assertEquals("Zero",layout.getValue(0, segment));
- assertEquals("One",layout.getValue(1, segment));
+ assertNull(layout.getValue(-1, segment.getConstantPool()));
+ assertEquals("Zero",layout.getValue(0, segment.getConstantPool()));
+ assertEquals("One",layout.getValue(1, segment.getConstantPool()));
}
public void testLayoutRUN() throws Pack200Exception {
AttributeLayout layout = new AttributeLayout("RUN",AttributeLayout.CONTEXT_CLASS,"RUN", 1);
@@ -62,9 +63,9 @@
public void testLayoutRUN() throws Pack200Exception {
AttributeLayout layout = new AttributeLayout("RUN",AttributeLayout.CONTEXT_CLASS,"RUN", 1);
Segment segment = new TestSegment();
- assertNull(layout.getValue(0, segment));
- assertEquals("Zero",layout.getValue(1, segment));
- assertEquals("One",layout.getValue(2, segment));
+ assertNull(layout.getValue(0, segment.getConstantPool()));
+ assertEquals("Zero",layout.getValue(1, segment.getConstantPool()));
+ assertEquals("One",layout.getValue(2, segment.getConstantPool()));
}
public void testLayoutRS() throws Pack200Exception {
AttributeLayout layout = new AttributeLayout("RS",AttributeLayout.CONTEXT_CLASS,"RS", 1);
@@ -69,9 +70,9 @@
public void testLayoutRS() throws Pack200Exception {
AttributeLayout layout = new AttributeLayout("RS",AttributeLayout.CONTEXT_CLASS,"RS", 1);
Segment segment = new TestSegment();
- assertNull(layout.getValue(-1, segment));
- assertEquals("Ein",layout.getValue(0, segment));
- assertEquals("Zwei",layout.getValue(1, segment));
+ assertNull(layout.getValue(-1, segment.getConstantPool()));
+ assertEquals("Ein",layout.getValue(0, segment.getConstantPool()));
+ assertEquals("Zwei",layout.getValue(1, segment.getConstantPool()));
}
public void testLayoutRSN() throws Pack200Exception {
AttributeLayout layout = new AttributeLayout("RSN",AttributeLayout.CONTEXT_CLASS,"RSN", 1);
@@ -76,9 +77,9 @@
public void testLayoutRSN() throws Pack200Exception {
AttributeLayout layout = new AttributeLayout("RSN",AttributeLayout.CONTEXT_CLASS,"RSN", 1);
Segment segment = new TestSegment();
- assertNull(layout.getValue(0, segment));
- assertEquals("Ein",layout.getValue(1, segment));
- assertEquals("Zwei",layout.getValue(2, segment));
+ assertNull(layout.getValue(0, segment.getConstantPool()));
+ assertEquals("Ein",layout.getValue(1, segment.getConstantPool()));
+ assertEquals("Zwei",layout.getValue(2, segment.getConstantPool()));
}
public boolean throwsException(String name, int context, String layout) {
try {
Index: src/test/java/org/apache/harmony/pack200/tests/BandSetTest.java
===================================================================
--- src/test/java/org/apache/harmony/pack200/tests/BandSetTest.java
+++ src/test/java/org/apache/harmony/pack200/tests/BandSetTest.java
@@ -0,0 +1,88 @@
+/*
+ * 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 java.io.InputStream;
+import java.io.OutputStream;
+
+import junit.framework.TestCase;
+
+import org.apache.harmony.pack200.BHSDCodec;
+import org.apache.harmony.pack200.BandSet;
+import org.apache.harmony.pack200.Codec;
+import org.apache.harmony.pack200.Pack200Exception;
+import org.apache.harmony.pack200.Segment;
+
+public class BandSetTest extends TestCase {
+
+ private BandSet bandSet = new BandSet(new Segment()) {
+
+ public void pack(OutputStream outputStream) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void unpack(InputStream inputStream) throws IOException, Pack200Exception {
+ // TODO Auto-generated method stub
+
+ }
+ };
+
+ public void testDecodeBandInt() throws IOException, Pack200Exception {
+ BHSDCodec codec = Codec.BYTE1;
+ byte[] bytes = new byte[]{(byte)3,(byte)56,(byte)122,(byte)78};
+ InputStream in = new ByteArrayInputStream(bytes);
+ int[] ints = bandSet.decodeBandInt("Test Band", in, codec, 4);
+ for (int i = 0; i < ints.length; i++) {
+ assertEquals("Wrong value in position " + i, ints[i], bytes[i]);
+ }
+ }
+
+ 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};
+ InputStream in = new ByteArrayInputStream(bytes);
+ long[] longs = bandSet.decodeBandLong("Test Band", in, codec, 4);
+ for (int i = 0; i < longs.length; i++) {
+ assertEquals("Wrong value in position " + i, longs[i], bytes[i]);
+ }
+ //TODO: Should test this with other Codecs.
+ }
+
+ public void testParseFlags1() {
+
+ }
+
+ public void testParseFlags2() {
+
+ }
+
+ public void testParseFlags3() {
+
+ }
+
+ public void testParseReferences1() {
+
+ }
+
+ public void testParseReferences2() {
+
+ }
+
+}