Index: /Users/alex/Documents/Harmony/Workspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/Pack200Exception.java
===================================================================
--- /Users/alex/Documents/Harmony/Workspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/Pack200Exception.java (revision 464089)
+++ /Users/alex/Documents/Harmony/Workspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/Pack200Exception.java (working copy)
@@ -15,7 +15,9 @@
* limitations under the License.
*/
package org.apache.harmony.archive.internal.pack200;
-
+//NOTE: Do not use generics in this code; it needs to run on JVMs < 1.5
+//NOTE: Do not extract strings as messages; this code is still a work-in-progress
+//NOTE: Also, don't get rid of 'else' statements for the hell of it ...
/**
* Represents a problem with a Pack200 coding/decoding issue.
*
@@ -26,7 +28,7 @@
private static final long serialVersionUID = 5168177401552611803L;
- /**
+ /**
* Create a new Pack200 exception with the given message and cause
*
* @param message
Index: /Users/alex/Documents/Harmony/Workspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/AttributeLayoutMap.java
===================================================================
--- /Users/alex/Documents/Harmony/Workspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/AttributeLayoutMap.java (revision 0)
+++ /Users/alex/Documents/Harmony/Workspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/AttributeLayoutMap.java (revision 0)
@@ -0,0 +1,107 @@
+/*
+ * 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.archive.internal.pack200;
+//NOTE: Do not use generics in this code; it needs to run on JVMs < 1.5
+//NOTE: Do not extract strings as messages; this code is still a work-in-progress
+//NOTE: Also, don't get rid of 'else' statements for the hell of it ...
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Stores a mapping from attribute names to their corresponding layout types.
+ * Note that names of attribute layouts and their formats are not
+ * internationalised, and should not be translated.
+ */
+public class AttributeLayoutMap {
+ // private static final String METADATA = "[NH[(1)]][RSHNH[RUH(1)]][TB(66,67,73,83,90)[KIH](68)[KDH](70)[KFH](74)[KJH](99)[RSH](101)[RSHRUH](115)[RUH](91)[NH[(0)]](64)[RSH[RUH(0)]]()[]]";
+
+ // create a whole bunch of AttributeLayouts here
+ private static AttributeLayout[] getDefaultAttributeLayouts()
+ throws Pack200Exception {
+ return new AttributeLayout[] {
+ new AttributeLayout("LineNumberTable",
+ AttributeLayout.CONTEXT_CODE, "NH[PHH]", 1),
+ new AttributeLayout("LocalVariableTable",
+ AttributeLayout.CONTEXT_CODE, "NH[PHOHRUHRSHH]", 2),
+ new AttributeLayout("LocalVariableTypeTable",
+ AttributeLayout.CONTEXT_CODE, "NH[PHOHRUHRSHH]", 3),
+ new AttributeLayout("SourceFile",
+ AttributeLayout.CONTEXT_CLASS, "RUNH", 17),
+ new AttributeLayout("ConstantValue",
+ AttributeLayout.CONTEXT_FIELD, "KQH", 17),
+ new AttributeLayout("Code", AttributeLayout.CONTEXT_METHOD,
+ "*", 17),
+ new AttributeLayout("EnclosingMethod",
+ AttributeLayout.CONTEXT_CLASS, "RCHRDNH", 18),
+ new AttributeLayout("Exceptions",
+ AttributeLayout.CONTEXT_METHOD, "NH[RCH]", 18),
+ new AttributeLayout("Signature", AttributeLayout.CONTEXT_CLASS,
+ "RSH", 19),
+ new AttributeLayout("Signature", AttributeLayout.CONTEXT_FIELD,
+ "RSH", 19),
+ new AttributeLayout("Signature",
+ AttributeLayout.CONTEXT_METHOD, "RSH", 19),
+ new AttributeLayout("Deprecated",
+ AttributeLayout.CONTEXT_CLASS, "", 20),
+ new AttributeLayout("Deprecated",
+ AttributeLayout.CONTEXT_FIELD, "", 20),
+ new AttributeLayout("Deprecated",
+ AttributeLayout.CONTEXT_METHOD, "", 20),
+ new AttributeLayout("RuntimeVisibleAnnotations",
+ AttributeLayout.CONTEXT_CLASS, "*", 21),
+ new AttributeLayout("RuntimeVisibleAnnotations",
+ AttributeLayout.CONTEXT_FIELD, "*", 21),
+ new AttributeLayout("RuntimeVisibleAnnotations",
+ AttributeLayout.CONTEXT_METHOD, "*", 21),
+ new AttributeLayout("RuntimeInvisibleAnnotations",
+ AttributeLayout.CONTEXT_CLASS, "*", 22),
+ new AttributeLayout("RuntimeInvisibleAnnotations",
+ AttributeLayout.CONTEXT_FIELD, "*", 22),
+ new AttributeLayout("RuntimeInvisibleAnnotations",
+ AttributeLayout.CONTEXT_METHOD, "*", 22),
+ new AttributeLayout("InnerClasses",
+ AttributeLayout.CONTEXT_CLASS, "*", 23),
+ new AttributeLayout("RuntimeVisibleParameterAnnotations",
+ AttributeLayout.CONTEXT_METHOD, "*", 23),
+ new AttributeLayout("class-file version",
+ AttributeLayout.CONTEXT_CLASS, "*", 24),
+ new AttributeLayout("RuntimeInvisibleParameterAnnotations",
+ AttributeLayout.CONTEXT_METHOD, "*", 24),
+ new AttributeLayout("AnnotationDefault",
+ AttributeLayout.CONTEXT_METHOD, "*", 25) };
+ }
+
+ private Map layouts;
+
+ public AttributeLayoutMap() throws Pack200Exception {
+ this.layouts = new HashMap();
+ AttributeLayout[] defaultAttributeLayouts = getDefaultAttributeLayouts();
+ for (int i = 0; i < defaultAttributeLayouts.length; i++) {
+ add(defaultAttributeLayouts[i]);
+ }
+ }
+
+ public void add(AttributeLayout layout) {
+ layouts.put(layout.key, layout);
+ }
+
+ public AttributeLayout getAttributeLayout(String name, int context)
+ throws Pack200Exception {
+ return (AttributeLayout) layouts.get(new AttributeLayout.Key(name,
+ context));
+ }
+}
Index: /Users/alex/Documents/Harmony/Workspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/AttributeLayout.java
===================================================================
--- /Users/alex/Documents/Harmony/Workspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/AttributeLayout.java (revision 0)
+++ /Users/alex/Documents/Harmony/Workspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/AttributeLayout.java (revision 0)
@@ -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.archive.internal.pack200;
+//NOTE: Do not use generics in this code; it needs to run on JVMs < 1.5
+//NOTE: Do not extract strings as messages; this code is still a work-in-progress
+//NOTE: Also, don't get rid of 'else' statements for the hell of it ...
+import org.apache.harmony.archive.internal.pack200.Segment.SegmentConstantPool;
+
+public class AttributeLayout {
+ static class Key {
+ public Key(String name, int context) throws Pack200Exception {
+ if (name == null || name.length() == 0)
+ throw new Pack200Exception("Cannot have an unnamed layout");
+ if (context != CONTEXT_CLASS && context != CONTEXT_CODE
+ && context != CONTEXT_FIELD && context != CONTEXT_METHOD)
+ throw new Pack200Exception("Attribute context out of range: "
+ + context);
+ this.name = name;
+ this.context = context;
+
+ }
+
+ private int context;
+
+ private String name;
+
+ @Override
+ public int hashCode() {
+ final int PRIME = 31;
+ int result = 1;
+ result = PRIME * result + context;
+ result = PRIME * result + ((name == null) ? 0 : name.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ final Key other = (Key) obj;
+ if (context != other.context)
+ return false;
+ if (name == null) {
+ if (other.name != null)
+ return false;
+ } else if (!name.equals(other.name))
+ return false;
+ return true;
+ }
+
+ public String toString() {
+ return contextNames[context] + ": " + name;
+ }
+
+ }
+
+ private String layout;
+
+ Key key;
+
+ private long mask;
+
+ public static final int CONTEXT_CODE = 1 << 4;
+
+ public static final int CONTEXT_CLASS = 1 << 0;
+
+ public static final int CONTEXT_FIELD = 1 << 2;
+
+ public static final int CONTEXT_METHOD = 1 << 3;
+
+ private static final String[] contextNames = { "Class", "Field", "Method",
+ "Code", };
+
+ public Codec getCodec() {
+ if (layout.indexOf("O") >= 0) {
+ return Codec.BRANCH5;
+ } else if (layout.indexOf("P") >= 0) {
+ return Codec.BCI5;
+ } else if (layout.indexOf("S") >= 0 && layout.indexOf("KS") < 0
+ && layout.indexOf("RS") < 0) {
+ return Codec.SIGNED5;
+ } else if (layout.indexOf("B") >= 0) {
+ return Codec.BYTE1;
+ }
+ /*
+ * TODO Add this as a test (and don't commit since this is copyright
+ * text) && ) If the layout contains 'O', use BRANCH5. Otherwise, if the
+ * layout contains 'P', use BCI5. Otherwise, if the layout contains 'S'
+ * but not 'KS' or 'RS', use SIGNED5. Otherwise, if the layout contains
+ * 'B', use BYTE1. For all other layouts use UNSIGNED5.
+ */
+ else {
+ return Codec.UNSIGNED5;
+ }
+ }
+
+ public Object getValue(long value, Segment segment) throws Pack200Exception {
+ if (layout.startsWith("R")) {
+ // references
+ if (layout.indexOf('N') != -1)
+ value--;
+ SegmentConstantPool pool = segment.getConstantPool();
+ if (layout.startsWith("RU")) {
+ return pool.getValue(SegmentConstantPool.UTF_8, value);
+ } else if (layout.startsWith("RS")) {
+ return pool.getValue(SegmentConstantPool.SIGNATURE, value);
+ }
+ }
+ throw new Pack200Exception("Unknown layout encoding: " + layout);
+ }
+
+ public AttributeLayout(String name, int context, String layout, int index)
+ throws Pack200Exception {
+ super();
+ this.key = new Key(name, context);
+ if (index >= 0) {
+ this.mask = 1L << index;
+ } else {
+ this.mask = 0;
+ }
+ if (layout == null) // || layout.length() == 0)
+ throw new Pack200Exception("Cannot have a null layout");
+ this.layout = layout;
+ }
+
+ public boolean isCode() {
+ return key.context == CONTEXT_CODE;
+ }
+
+ public boolean isClass() {
+ return key.context == CONTEXT_CLASS;
+ }
+
+ public boolean isMethod() {
+ return key.context == CONTEXT_METHOD;
+ }
+
+ public boolean isField() {
+ return key.context == CONTEXT_FIELD;
+ }
+
+ public int hashCode() {
+ return key.hashCode();
+ }
+
+ public boolean matches(long value) {
+ return (value & mask) != 0;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ final AttributeLayout other = (AttributeLayout) obj;
+ if (key == null) {
+ if (other.key != null)
+ return false;
+ } else if (!key.equals(other.key))
+ return false;
+ if (layout == null) {
+ if (other.layout != null)
+ return false;
+ } else if (!layout.equals(other.layout))
+ return false;
+ return true;
+ }
+
+ public String toString() {
+ return key.toString();
+ }
+
+ public String getLayout() {
+ return layout;
+ }
+
+}
Index: /Users/alex/Documents/Harmony/Workspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/Segment.java
===================================================================
--- /Users/alex/Documents/Harmony/Workspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/Segment.java (revision 464089)
+++ /Users/alex/Documents/Harmony/Workspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/Segment.java (working copy)
@@ -15,15 +15,20 @@
* limitations under the License.
*/
package org.apache.harmony.archive.internal.pack200;
-
+//NOTE: Do not use generics in this code; it needs to run on JVMs < 1.5
+//NOTE: Do not extract strings as messages; this code is still a work-in-progress
+//NOTE: Also, don't get rid of 'else' statements for the hell of it ...
import java.io.ByteArrayInputStream;
+import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
import java.util.zip.GZIPInputStream;
-import org.apache.harmony.archive.internal.nls.Messages;
+import org.apache.harmony.archive.internal.pack200.ClassFileEntry.SourceFile;
/**
* A Pack200 archive consists of one (or more) segments. Each segment is
@@ -57,6 +62,29 @@
* @version $Revision: $
*/
public class Segment {
+ public class SegmentConstantPool {
+ public static final int ALL = 0;
+
+ public static final int SIGNATURE = 2; // TODO and more to come --
+ // define in archive order
+
+ 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;
+ if (index < 0)
+ throw new Pack200Exception("Cannot have a negative range");
+ if (cp == UTF_8)
+ return cpUTF8[index];
+ if (cp == SIGNATURE)
+ return cpSignature[index];
+ // etc
+ throw new Error("Get value incomplete");
+ }
+ }
+
/**
* The magic header for a Pack200 Segment is 0xCAFED00D. I wonder where they
* get their inspiration from ...
@@ -106,12 +134,12 @@
throws IOException, Pack200Exception {
int total = in.read(data);
if (total == -1)
- throw new EOFException(Messages.getString("archive.0E")); //$NON-NLS-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(
- Messages.getString("archive.0D")); //$NON-NLS-1$
+ "Failed to read some data from input stream");
total += delta;
}
}
@@ -126,16 +154,22 @@
private String[] attributeDefinitionLayout;
+ private AttributeLayoutMap attributeDefinitionMap;
+
private String[] attributeDefinitionName;
private InputStream bandHeadersInputStream;
private int bandHeadersSize;
+ private int classAttrCount;
+
private int classCount;
private int[] classFieldCount;
+ private long[] classFlags;
+
private String[][] classInterfaces;
private int[] classMethodCount;
@@ -228,7 +262,7 @@
private int innerClassCount;
- private int major;
+ private int archiveMajor;
private int methodAttrCount;
@@ -236,18 +270,16 @@
private long[][] methodFlags;
- private int minor;
+ private int archiveMinor;
private int numberOfFiles;
private SegmentOptions options;
+ private final SegmentConstantPool pool = new SegmentConstantPool();
+
private int segmentsRemaining;
- private int classAttrCount;
-
- private long[] classFlags;
-
/**
* 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
@@ -258,7 +290,7 @@
* @deprecated this should be removed from production code
*/
@Deprecated
- private void debug(String message) {
+ private void debug(String message) {
if (System.getProperty("debug.pack200") != null) {
System.err.println(message);
}
@@ -423,10 +455,97 @@
}
+ public SegmentConstantPool getConstantPool() {
+ return pool;
+ }
+
public int getNumberOfFiles() {
return numberOfFiles;
}
+ /**
+ * 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 0)
- throw new Error(Messages.getString("archive.0C")); //$NON-NLS-1$
+ throw new Error("No idea what the adc is for yet");
+ attributeDefinitionMap = new AttributeLayoutMap();
}
private void parseBcBands(InputStream in) {
@@ -499,10 +619,22 @@
classAttrCount++;
}
if (classAttrCount > 0)
- throw new Error(Messages.getString("archive.0A")); //$NON-NLS-1$
+ 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(
+ "SourceFile", 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
+ long result = layout.getCodec().decode(in);
+ Object value = layout.getValue(result, this);
+ debug("Processed value " + value + " for SourceFile");
+ }
+ }
debug("unimplemented class_SourceFile_RUN");
debug("unimplemented class_EnclosingMethod_RC");
debug("unimplemented class_EnclosingMethod_RDN");
@@ -550,18 +682,6 @@
setClassCount(decodeScalar("class_count", in, Codec.UNSIGNED5));
}
- private void parseCodeBands(InputStream in) {
- debug("unimplemented code_headers");
- debug("unimplemented code_max_stack");
- debug("unimplemented code_max_na_locals");
- debug("unimplemented code_hander_count");
- debug("unimplemented code_hander_start_P");
- debug("unimplemented code_hander_end_PO");
- debug("unimplemented code_hander_catch_PO");
- debug("unimplemented code_hander_class_RC");
- parseCodeAttrBands(in);
- }
-
private void parseCodeAttrBands(InputStream in) {
debug("unimplemented code_flags");
debug("unimplemented code_attr_count");
@@ -582,6 +702,18 @@
}
}
+ private void parseCodeBands(InputStream in) {
+ debug("unimplemented code_headers");
+ debug("unimplemented code_max_stack");
+ debug("unimplemented code_max_na_locals");
+ debug("unimplemented code_hander_count");
+ debug("unimplemented code_hander_start_P");
+ debug("unimplemented code_hander_end_PO");
+ debug("unimplemented code_hander_catch_PO");
+ debug("unimplemented code_hander_class_RC");
+ parseCodeAttrBands(in);
+ }
+
/**
* Parses the constant pool class names, using {@link #cpClassCount} to
* populate {@link #cpClass} from {@link #cpUTF8}.
@@ -779,7 +911,7 @@
String form = cpSignatureForm[i];
int len = form.length();
StringBuffer signature = new StringBuffer(64);
- ArrayList list = new ArrayList();
+ ArrayList list = new ArrayList();
for (int j = 0; j < len; j++) {
char c = form.charAt(j);
signature.append(c);
@@ -1005,38 +1137,6 @@
cpUTF8);
}
- private void parseMethodBands(InputStream in) throws IOException,
- Pack200Exception {
- methodDescr = new String[classCount][];
- for (int i = 0; i < classCount; i++) {
- methodDescr[i] = parseReferences("method_descr", in, Codec.MDELTA5,
- classMethodCount[i], cpDescriptor);
- }
- methodFlags = new long[classCount][];
- for (int i = 0; i < classCount; i++) {
- methodFlags[i] = parseFlags("method_flags", in,
- classMethodCount[i], Codec.UNSIGNED5, options
- .hasMethodFlagsHi());
- }
- for (int i = 0; i < classCount; i++) {
- for (int j = 0; j < methodFlags[i].length; j++) {
- long flag = methodFlags[i][j];
- if ((flag & (1 << 16)) != 0)
- methodAttrCount++;
- }
- }
- if (methodAttrCount > 0)
- throw new Error(
- "There are method attribute flags, and I don't know what to do with them");
- debug("unimplemented method_attr_count");
- debug("unimplemented method_attr_indexes");
- debug("unimplemented method_attr_calls");
- debug("unimplemented method_Exceptions_N");
- debug("unimplemented method_Exceptions_RC");
- debug("unimplemented method_Signature_RS");
- parseMetadataBands("method");
- }
-
private void parseMetadataBands(String unit) throws Pack200Exception {
String[] RxA;
if ("method".equals(unit)) {
@@ -1073,6 +1173,38 @@
}
}
+ private void parseMethodBands(InputStream in) throws IOException,
+ Pack200Exception {
+ methodDescr = new String[classCount][];
+ for (int i = 0; i < classCount; i++) {
+ methodDescr[i] = parseReferences("method_descr", in, Codec.MDELTA5,
+ classMethodCount[i], cpDescriptor);
+ }
+ methodFlags = new long[classCount][];
+ for (int i = 0; i < classCount; i++) {
+ methodFlags[i] = parseFlags("method_flags", in,
+ classMethodCount[i], Codec.UNSIGNED5, options
+ .hasMethodFlagsHi());
+ }
+ for (int i = 0; i < classCount; i++) {
+ for (int j = 0; j < methodFlags[i].length; j++) {
+ long flag = methodFlags[i][j];
+ if ((flag & (1 << 16)) != 0)
+ methodAttrCount++;
+ }
+ }
+ if (methodAttrCount > 0)
+ throw new Error(
+ "There are method attribute flags, and I don't know what to do with them");
+ debug("unimplemented method_attr_count");
+ debug("unimplemented method_attr_indexes");
+ debug("unimplemented method_attr_calls");
+ debug("unimplemented method_Exceptions_N");
+ debug("unimplemented method_Exceptions_RC");
+ debug("unimplemented method_Signature_RS");
+ parseMetadataBands("method");
+ }
+
/**
* Helper method to parse count references from in,
* using codec to decode the values as indexes into
@@ -1107,7 +1239,7 @@
int index = decode[i];
if (index < 0 || index >= reference.length)
throw new Pack200Exception(
- Messages.getString("archive.06")); //$NON-NLS-1$
+ "Something has gone wrong during parsing references");
result[i] = reference[index];
}
return result;
@@ -1130,7 +1262,7 @@
debug("-------");
parseSegmentHeader(in);
if (bandHeadersSize > 0) {
- byte[] bandHeaders = new byte[bandHeadersSize];
+ byte[] bandHeaders = new byte[(int) bandHeadersSize];
readFully(in, bandHeaders);
setBandHeadersData(bandHeaders);
}
@@ -1151,9 +1283,7 @@
parseClassBands(in);
parseBcBands(in);
// TODO Re-enable these after completing class/bytecode bands
- // parseFileBands(in);
- // processFileBits(in); // this just caches them in file_bits; it should
- // probably start writing here?
+ parseFileBands(in);
}
private void parseSegmentHeader(InputStream in) throws IOException,
@@ -1162,10 +1292,10 @@
magic.length);
for (int m = 0; m < magic.length; m++)
if (word[m] != magic[m])
- throw new Error(Messages.getString("archive.07")); //$NON-NLS-1$
- setMinorVersion((int) decodeScalar("archive_minver", in,
+ throw new Error("Bad header");
+ setArchiveMinorVersion((int) decodeScalar("archive_minver", in,
Codec.UNSIGNED5));
- setMajorVersion((int) decodeScalar("archive_majver", in,
+ setArchiveMajorVersion((int) decodeScalar("archive_majver", in,
Codec.UNSIGNED5));
setOptions(new SegmentOptions((int) decodeScalar("archive_options", in,
Codec.UNSIGNED5)));
@@ -1283,10 +1413,10 @@
* @throws Pack200Exception
* if the major version is not 150
*/
- private void setMajorVersion(int version) throws Pack200Exception {
+ private void setArchiveMajorVersion(int version) throws Pack200Exception {
if (version != 150)
- throw new Pack200Exception(Messages.getString("archive.08")); //$NON-NLS-1$
- major = version;
+ throw new Pack200Exception("Invalid segment major version");
+ archiveMajor = version;
}
/**
@@ -1297,10 +1427,10 @@
* @throws Pack200Exception
* if the minor version is not 7
*/
- private void setMinorVersion(int version) throws Pack200Exception {
+ private void setArchiveMinorVersion(int version) throws Pack200Exception {
if (version != 7)
- throw new Pack200Exception(Messages.getString("archive.09")); //$NON-NLS-1$
- minor = version;
+ throw new Pack200Exception("Invalid segment minor version");
+ archiveMinor = version;
}
public void setNumberOfFiles(long value) {
Index: /Users/alex/Documents/Harmony/Workspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/RunCodec.java
===================================================================
--- /Users/alex/Documents/Harmony/Workspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/RunCodec.java (revision 464089)
+++ /Users/alex/Documents/Harmony/Workspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/RunCodec.java (working copy)
@@ -15,12 +15,12 @@
* limitations under the License.
*/
package org.apache.harmony.archive.internal.pack200;
-
+//NOTE: Do not use generics in this code; it needs to run on JVMs < 1.5
+//NOTE: Do not extract strings as messages; this code is still a work-in-progress
+//NOTE: Also, don't get rid of 'else' statements for the hell of it ...
import java.io.IOException;
import java.io.InputStream;
-import org.apache.harmony.archive.internal.nls.Messages;
-
/**
* A run codec is a grouping of two nested codecs; K values are decoded from
* the first codec, and the remaining codes are decoded from the remaining
@@ -38,32 +38,28 @@
public RunCodec(int k, Codec aCodec, Codec bCodec) throws Pack200Exception {
if (k <= 0)
- throw new Pack200Exception(Messages.getString("archive.12")); //$NON-NLS-1$
+ throw new Pack200Exception("Cannot have a RunCodec for a negative number of numbers");
if (aCodec == null || bCodec == null)
- throw new Pack200Exception(Messages.getString("archive.13")); //$NON-NLS-1$
+ throw new Pack200Exception("Must supply both codecs for a RunCodec");
this.k = k;
this.aCodec = aCodec;
this.bCodec = bCodec;
}
-
- @Override
- public long decode(InputStream in) throws IOException, Pack200Exception {
+ public long decode(InputStream in) throws IOException, Pack200Exception {
return decode(in,this.last);
}
- @Override
- public long decode(InputStream in, long last) throws IOException, Pack200Exception {
+ public long decode(InputStream in, long last) throws IOException, Pack200Exception {
if(--k>=0) {
long value = aCodec.decode(in,last);
this.last = (k == 0 ? 0 : value);
return value;
+ } else {
+ this.last = bCodec.decode(in,last);
+ return this.last;
}
- this.last = bCodec.decode(in,last);
- return this.last;
}
-
- @Override
- public String toString() {
- return "RunCodec[k="+k+";aCodec="+aCodec+"bCodec="+bCodec+"]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ public String toString() {
+ return "RunCodec[k="+k+";aCodec="+aCodec+"bCodec="+bCodec+"]";
}
}
Index: /Users/alex/Documents/Harmony/Workspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/CodecEncoding.java
===================================================================
--- /Users/alex/Documents/Harmony/Workspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/CodecEncoding.java (revision 464089)
+++ /Users/alex/Documents/Harmony/Workspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/CodecEncoding.java (working copy)
@@ -15,13 +15,13 @@
* limitations under the License.
*/
package org.apache.harmony.archive.internal.pack200;
-
+//NOTE: Do not use generics in this code; it needs to run on JVMs < 1.5
+//NOTE: Do not extract strings as messages; this code is still a work-in-progress
+//NOTE: Also, don't get rid of 'else' statements for the hell of it ...
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
-import org.apache.harmony.archive.internal.nls.Messages;
-
public class CodecEncoding {
/**
* The canonical encodings are defined to allow a single byte to represent
@@ -103,10 +103,10 @@
// Sanity check to make sure that no-one's been buggering with
// the canonical codecs, which would really cause havoc
if (canonicalCodec.length != 116)
- throw new Error(Messages.getString("archive.00")); //$NON-NLS-1$
+ throw new Error("Canonical encodings have been incorrectly modified");
if (value < 0) {
throw new IllegalArgumentException(
- Messages.getString("archive.01")); //$NON-NLS-1$
+ "Encoding cannot be less than zero");
} else if (value == 0) {
return defaultCodec;
} else if (value <= 115) {
@@ -114,13 +114,13 @@
} else if (value == 116) {
int code = in.read();
if (code == -1)
- throw new EOFException(Messages.getString("archive.02")); //$NON-NLS-1$
+ throw new EOFException("End of buffer read whilst trying to decode codec");
int d = (code & 0x01);
int s = (code >> 1 & 0x03);
int b = (code >> 3 & 0x07) + 1; // this might result in an invalid number, but it's checked in the Codec constructor
code = in.read();
if (code == -1)
- throw new EOFException(Messages.getString("archive.03")); //$NON-NLS-1$
+ throw new EOFException("End of buffer read whilst trying to decode codec");
int h = code + 1;
// This handles the special cases for invalid combinations of data.
return new BHSDCodec(b,h,s,d);
@@ -132,7 +132,7 @@
boolean bdef = (offset >> 4 & 1) == 1;
// If both A and B use the default encoding, what's the point of having a run of default values followed by default values
if (adef && bdef)
- throw new Pack200Exception(Messages.getString("archive.04")); //$NON-NLS-1$
+ throw new Pack200Exception("ADef and BDef should never both be true");
int kb = (kbflag ? in.read() : 3);
int k = (kb+1) * (int)Math.pow(16, kx);
Codec aCodec, bCodec;
@@ -165,13 +165,14 @@
// number of items read from the fCodec. So we don't know in advance what
// the codec will be.
return new PopulationCodec(fCodec,l,uCodec);
+ } else {
+ Codec fCodec = (fdef ? defaultCodec : getCodec(in.read(),in,defaultCodec) );
+ Codec uCodec = (udef ? defaultCodec : getCodec(in.read(),in,defaultCodec) );
+ Codec tCodec = getCodec(in.read(),in,defaultCodec);
+ return new PopulationCodec(fCodec,uCodec,tCodec);
}
- Codec fCodec = (fdef ? defaultCodec : getCodec(in.read(),in,defaultCodec) );
- Codec uCodec = (udef ? defaultCodec : getCodec(in.read(),in,defaultCodec) );
- Codec tCodec = getCodec(in.read(),in,defaultCodec);
- return new PopulationCodec(fCodec,uCodec,tCodec);
} else {
- throw new Pack200Exception(Messages.getString("archive.05", value)); //$NON-NLS-1$
+ throw new Pack200Exception("Invalid codec encoding byte (" + value + ") found" );
}
}
}
Index: /Users/alex/Documents/Harmony/Workspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/ClassFile.java
===================================================================
--- /Users/alex/Documents/Harmony/Workspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/ClassFile.java (revision 0)
+++ /Users/alex/Documents/Harmony/Workspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/ClassFile.java (revision 0)
@@ -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.archive.internal.pack200;
+//NOTE: Do not use generics in this code; it needs to run on JVMs < 1.5
+//NOTE: Do not extract strings as messages; this code is still a work-in-progress
+//NOTE: Also, don't get rid of 'else' statements for the hell of it ...
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+import org.apache.harmony.archive.internal.pack200.ClassFileEntry.Attribute;
+
+public class ClassFile {
+ int major;
+ int minor;
+ private int magic = 0xCAFEBABE;
+ ClassConstantPool pool = new ClassConstantPool();
+ int accessFlags;
+ int thisClass;
+ int superClass;
+ int[] interfaces;
+ int[] fields;
+ int[] methods;
+ Attribute[] attributes;
+ public void write(DataOutputStream dos) throws IOException {
+ dos.writeInt(magic);
+ dos.writeShort(minor);
+ dos.writeShort(major);
+ dos.writeShort(pool.size()+1);
+ for(int i=1;i<=pool.size();i++) {
+ ConstantPoolEntry entry;
+ (entry = (ConstantPoolEntry)pool.get(i)).write(dos);
+ // Doubles and longs take up two spaces in the pool, but only one gets written
+ if (entry.getTag() == ConstantPoolEntry.CP_Double || entry.getTag() == ConstantPoolEntry.CP_Long)
+ i++;
+ };
+ dos.writeShort(accessFlags);
+ dos.writeShort(thisClass);
+ dos.writeShort(superClass);
+ dos.writeShort(interfaces.length);
+ for(int i=0;i= 256 || l <=0)
- throw new IllegalArgumentException(Messages.getString("archive.0F")); //$NON-NLS-1$
+ throw new IllegalArgumentException("L must be between 1..255");
this.favouredCodec = favouredCodec;
this.l = l;
this.unvafouredCodec = unvafouredCodec;
@@ -44,13 +43,13 @@
@Override
public long decode(InputStream in) throws IOException, Pack200Exception {
- throw new Pack200Exception(Messages.getString("archive.10")); //$NON-NLS-1$
+ throw new Pack200Exception("Population encoding does not work unless the number of elements are known");
}
@Override
public long decode(InputStream in, long last) throws IOException,
Pack200Exception {
- throw new Pack200Exception(Messages.getString("archive.10")); //$NON-NLS-1$
+ throw new Pack200Exception("Population encoding does not work unless the number of elements are known");
}
@Override
@@ -88,7 +87,7 @@
tokenCodec = codec;
}
if (tokenCodec == null)
- throw new Pack200Exception(Messages.getString("archive.11", new Integer(k), new Integer(l))); //$NON-NLS-1$
+ throw new Pack200Exception("Cannot calculate token codec from " + k + " and " + l);
}
}
// read favourites
Index: /Users/alex/Documents/Harmony/Workspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/ClassConstantPool.java
===================================================================
--- /Users/alex/Documents/Harmony/Workspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/ClassConstantPool.java (revision 0)
+++ /Users/alex/Documents/Harmony/Workspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/ClassConstantPool.java (revision 0)
@@ -0,0 +1,74 @@
+/*
+ * 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.archive.internal.pack200;
+
+// NOTE: Do not use generics in this code; it needs to run on JVMs < 1.5
+// NOTE: Do not extract strings as messages; this code is still a
+// work-in-progress
+// NOTE: Also, don't get rid of 'else' statements for the hell of it ...
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+public class ClassConstantPool {
+ private List others = new ArrayList();
+
+ private List entries = new ArrayList();
+
+ public void add(ClassFileEntry entry) {
+ // TODO this should be a set - we don't want duplicates
+ // Only add in constant pools, but resolve all types since they may
+ // introduce new constant pool entries
+ if (entry instanceof ConstantPoolEntry) {
+ if (!entries.contains(entry))
+ entries.add(entry);
+ } else {
+ if (!others.contains(entry))
+ others.add(entry);
+ }
+ ClassFileEntry[] nestedEntries = entry.getNestedClassFileEntries();
+ for (int i = 0; i < nestedEntries.length; i++) {
+ add(nestedEntries[i]);
+ }
+ }
+
+ public int indexOf(ClassFileEntry entry) {
+ return entries.indexOf(entry) + 1;
+ }
+
+ public int size() {
+ return entries.size();
+ }
+
+ public ClassFileEntry get(int i) {
+ return (ClassFileEntry) entries.get(--i);
+ }
+
+ public void resolve() {
+ Iterator it = entries.iterator();
+ while (it.hasNext()) {
+ ClassFileEntry entry = (ClassFileEntry) it.next();
+ entry.resolve(this);
+ }
+ it = others.iterator();
+ while (it.hasNext()) {
+ ClassFileEntry entry = (ClassFileEntry) it.next();
+ entry.resolve(this);
+ }
+ }
+
+}
Index: /Users/alex/Documents/Harmony/Workspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/Codec.java
===================================================================
--- /Users/alex/Documents/Harmony/Workspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/Codec.java (revision 464089)
+++ /Users/alex/Documents/Harmony/Workspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/Codec.java (working copy)
@@ -15,7 +15,9 @@
* limitations under the License.
*/
package org.apache.harmony.archive.internal.pack200;
-
+//NOTE: Do not use generics in this code; it needs to run on JVMs < 1.5
+//NOTE: Do not extract strings as messages; this code is still a work-in-progress
+//NOTE: Also, don't get rid of 'else' statements for the hell of it ...
import java.io.IOException;
import java.io.InputStream;
Index: /Users/alex/Documents/Harmony/Workspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/SegmentOptions.java
===================================================================
--- /Users/alex/Documents/Harmony/Workspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/SegmentOptions.java (revision 464089)
+++ /Users/alex/Documents/Harmony/Workspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/SegmentOptions.java (working copy)
@@ -15,9 +15,9 @@
* limitations under the License.
*/
package org.apache.harmony.archive.internal.pack200;
-
-import org.apache.harmony.archive.internal.nls.Messages;
-
+//NOTE: Do not use generics in this code; it needs to run on JVMs < 1.5
+//NOTE: Do not extract strings as messages; this code is still a work-in-progress
+//NOTE: Also, don't get rid of 'else' statements for the hell of it ...
/**
* Stores the combinations of bit flags that can be used in the segment header
* options. Whilst this could be defined in {@link Segment}, it's cleaner to
@@ -74,7 +74,7 @@
*/
public SegmentOptions(int options) throws Pack200Exception {
if ((options & UNUSED) != 0)
- throw new Pack200Exception(Messages.getString("archive.14")); //$NON-NLS-1$
+ throw new Pack200Exception("Some unused flags are non-zero");
this.options = options;
}
Index: /Users/alex/Documents/Harmony/Workspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/BHSDCodec.java
===================================================================
--- /Users/alex/Documents/Harmony/Workspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/BHSDCodec.java (revision 464088)
+++ /Users/alex/Documents/Harmony/Workspace/Pack200/src/main/java/org/apache/harmony/archive/internal/pack200/BHSDCodec.java (working copy)
@@ -15,13 +15,13 @@
* limitations under the License.
*/
package org.apache.harmony.archive.internal.pack200;
-
+//NOTE: Do not use generics in this code; it needs to run on JVMs < 1.5
+//NOTE: Do not extract strings as messages; this code is still a work-in-progress
+//NOTE: Also, don't get rid of 'else' statements for the hell of it ...
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
-import org.apache.harmony.archive.internal.nls.Messages;
-
/**
* TODO Comment -- quite a lot can be nicked from Codec, since this was created
* from it
@@ -102,17 +102,17 @@
*/
public BHSDCodec(int b, int h, int s, int d) {
if (b < 1 || b > 5)
- throw new IllegalArgumentException(Messages.getString("archive.15")); //$NON-NLS-1$
+ throw new IllegalArgumentException("1<=b<=5");
if (h < 1 || h > 256)
- throw new IllegalArgumentException(Messages.getString("archive.16")); //$NON-NLS-1$
+ throw new IllegalArgumentException("1<=h<=256");
if (s < 0 || s > 2)
- throw new IllegalArgumentException(Messages.getString("archive.17")); //$NON-NLS-1$
+ throw new IllegalArgumentException("0<=s<=2");
if (d < 0 || d > 1)
- throw new IllegalArgumentException(Messages.getString("archive.18")); //$NON-NLS-1$
+ throw new IllegalArgumentException("0<=d<=1");
if (b == 1 && h != 256)
- throw new IllegalArgumentException(Messages.getString("archive.19")); //$NON-NLS-1$
+ throw new IllegalArgumentException("b=1 -> h=256");
if (h == 256 && b == 5)
- throw new IllegalArgumentException(Messages.getString("archive.1A")); //$NON-NLS-1$
+ throw new IllegalArgumentException("h=256 -> b!=5");
this.b = b;
this.h = h;
this.s = s;
@@ -129,15 +129,16 @@
public long cardinality() {
if (h > 1) {
return (long) (l * Math.pow(1 - h, b) / (1 - h) + Math.pow(h, b));
+ } else {
+ return (b * 255) + 1;
}
- return (b * 255) + 1;
}
@Override
public long decode(InputStream in) throws IOException, Pack200Exception {
if (d != 0)
throw new Pack200Exception(
- Messages.getString("archive.1B")); //$NON-NLS-1$
+ "Delta encoding used without passing in last value; this is a coding error");
return decode(in, 0);
}
@@ -150,7 +151,7 @@
do {
x = in.read();
if (x == -1)
- throw new EOFException(Messages.getString("archive.1C")); //$NON-NLS-1$
+ throw new EOFException("End of stream reached whilst decoding");
z += x * Math.pow(h, n);
} while (++n < b && x >= l);
// This looks more complicated than it is
@@ -215,7 +216,7 @@
} else if (s == 2) {
result = (3L * cardinality()) / 4 - 1;
} else {
- throw new Error(Messages.getString("archive.1D")); //$NON-NLS-1$
+ throw new Error("Unknown s value");
}
}
return Math.min((s == 0 ? ((long) Integer.MAX_VALUE) << 1
@@ -243,19 +244,18 @@
* Returns the codec in the form (1,256) or (1,64,1,1). Note that trailing
* zero fields are not shown.
*/
- @Override
- public String toString() {
+ public String toString() {
StringBuffer buffer = new StringBuffer(11);
buffer.append('(');
buffer.append(b);
buffer.append(',');
buffer.append(h);
if (s != 0 || d != 0) {
- buffer.append(","); //$NON-NLS-1$
+ buffer.append(',');
buffer.append(s);
}
if (d != 0) {
- buffer.append(","); //$NON-NLS-1$
+ buffer.append(',');
buffer.append(d);
}
buffer.append(')');