You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by te...@apache.org on 2006/06/14 11:24:19 UTC
svn commit: r414164 - in
/incubator/harmony/enhanced/classlib/trunk/modules/archive: make/
src/main/java/org/ src/main/java/org/apache/
src/main/java/org/apache/harmony/ src/main/java/org/apache/harmony/archive/
src/main/java/org/apache/harmony/archive...
Author: tellison
Date: Wed Jun 14 02:24:18 2006
New Revision: 414164
URL: http://svn.apache.org/viewvc?rev=414164&view=rev
Log:
Applied HARMONY-599 (Pack200 implementation for Harmony (work in progress))
with package/type renaming.
Added:
incubator/harmony/enhanced/classlib/trunk/modules/archive/src/main/java/org/
incubator/harmony/enhanced/classlib/trunk/modules/archive/src/main/java/org/apache/
incubator/harmony/enhanced/classlib/trunk/modules/archive/src/main/java/org/apache/harmony/
incubator/harmony/enhanced/classlib/trunk/modules/archive/src/main/java/org/apache/harmony/archive/
incubator/harmony/enhanced/classlib/trunk/modules/archive/src/main/java/org/apache/harmony/archive/internal/
incubator/harmony/enhanced/classlib/trunk/modules/archive/src/main/java/org/apache/harmony/archive/internal/pack200/
incubator/harmony/enhanced/classlib/trunk/modules/archive/src/main/java/org/apache/harmony/archive/internal/pack200/Codec.java (with props)
incubator/harmony/enhanced/classlib/trunk/modules/archive/src/main/java/org/apache/harmony/archive/internal/pack200/Pack200Exception.java (with props)
incubator/harmony/enhanced/classlib/trunk/modules/archive/src/main/java/org/apache/harmony/archive/internal/pack200/Segment.java (with props)
incubator/harmony/enhanced/classlib/trunk/modules/archive/src/main/java/org/apache/harmony/archive/internal/pack200/SegmentOptions.java (with props)
incubator/harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/internal/
incubator/harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/internal/pack200/
incubator/harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/internal/pack200/CodecTest.java (with props)
incubator/harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/internal/pack200/HelloWorld.java (with props)
incubator/harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/internal/pack200/HelloWorld.pack (with props)
incubator/harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/internal/pack200/SegmentOptionsTest.java (with props)
incubator/harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/internal/pack200/SegmentTest.java (with props)
Modified:
incubator/harmony/enhanced/classlib/trunk/modules/archive/make/patternset.txt
Modified: incubator/harmony/enhanced/classlib/trunk/modules/archive/make/patternset.txt
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/archive/make/patternset.txt?rev=414164&r1=414163&r2=414164&view=diff
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/archive/make/patternset.txt (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/archive/make/patternset.txt Wed Jun 14 02:24:18 2006
@@ -13,4 +13,6 @@
# limitations under the License.
java/util/jar/*
-java/util/zip/*
\ No newline at end of file
+java/util/zip/*
+
+org/apache/harmony/archive/**
Added: incubator/harmony/enhanced/classlib/trunk/modules/archive/src/main/java/org/apache/harmony/archive/internal/pack200/Codec.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/archive/src/main/java/org/apache/harmony/archive/internal/pack200/Codec.java?rev=414164&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/archive/src/main/java/org/apache/harmony/archive/internal/pack200/Codec.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/archive/src/main/java/org/apache/harmony/archive/internal/pack200/Codec.java Wed Jun 14 02:24:18 2006
@@ -0,0 +1,342 @@
+/*
+ * Copyright 2006 The Apache Software Foundation or its licensors,
+ * as applicable.
+ *
+ * Licensed 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;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * A codec allows a sequence of bytes to be decoded into integer values (or vice
+ * versa). It uses a variable-length encoding and a modified sign representation
+ * such that small numbers are represented as a single byte, whilst larger
+ * numbers take more bytes to encode. The number may be signed or unsigned; if
+ * it is unsigned, it can be weighted towards positive numbers or equally
+ * distributed using a one's complement. The codec also supports delta coding,
+ * where a sequence of numbers is represented as a series of first-order
+ * differences. So a delta encoding of the integers [1..10] would be represented
+ * as a sequence of 10x1s. This allows the absolute value of a coded integer to
+ * fall outside of the 'small number' range, whilst still being encoded as a
+ * single byte.
+ *
+ * A codec is configured with four parameters:
+ * <dl>
+ * <dt>B</dt>
+ * <dd>The maximum number of bytes that each value is encoded as. B must be a
+ * value between [1..5]. For a pass-through coding (where each byte is encoded
+ * as itself, aka {@link #BYTE1}, B is 1 (each byte takes a maximum of 1 byte).</dd>
+ * <dt>H</dt>
+ * <dd>The radix of the integer. Values are defined as a sequence of values,
+ * where value <code>n</code> is multipled by <code>H^<sup>n</sup></code>.
+ * So the number 1234 may be represented as the sequence 4 3 2 1 with a radix
+ * (H) of 10. Note that other permutations are also possible; 43 2 1 will also
+ * encode 1234. The co-parameter L is defined as 256-H. This is important
+ * because only the last value in a sequence may be < L; all prior values
+ * must be > L.</dd>
+ * <dt>S</dt>
+ * <dd>Whether the codec represents signed values (or not). This may have 3
+ * values; 0 (unsigned), 1 (signed, ones complement) or 2 (signed, but not sure
+ * what the difference is) TODO Update documentation when I know what the
+ * difference is</dd>
+ * <dt>D</dt>
+ * <dd>Whether the codec represents a delta encoding. This may be 0 (no delta)
+ * or 1 (delta encoding). A delta encoding of 1 indicates that values are
+ * cumulative; a sequence of <code>1 1 1 1 1</code> will represent the
+ * sequence <code>1 2 3 4 5</code>. For this reason, the codec supports two
+ * variants of decode; one {@link #decode(InputStream, long) with} and one
+ * {@link #decode(InputStream) without} a <code>last</code> parameter. If the
+ * codec is a non-delta encoding, then the value is ignored if passed. If the
+ * codec is a delta encoding, it is a run-time error to call the value without
+ * the extra parameter, and the previous value should be returned. (It was
+ * designed this way to support multi-threaded access without requring a new
+ * instance of the Codec to be cloned for each use.)
+ * <dt>
+ * </dl>
+ *
+ * Codecs are notated as (B,H,S,D) and either D or S,D may be omitted if zero.
+ * Thus {@link #BYTE1} is denoted (1,256,0,0) or (1,256). The
+ * {@link #toString()} method prints out the condensed form of the encoding.
+ * Often, the last character in the name ({@link #BYTE1}, {@link #UNSIGNED5})
+ * gives a clue as to the B value. Those that start with U ({@link #UDELTA5},
+ * {@link #UNSIGNED5}) are unsigned; otherwise, in most cases, they are signed.
+ * The presence of the word Delta ({@link #DELTA5}, {@link #UDELTA5})
+ * indicates a delta encoding is used.
+ *
+ * This codec is really quite cool for storing compressed information, and could
+ * be used entirely separately from the Pack200 implementation for efficient
+ * transfer of integer data if required.
+ *
+ * Note that all information is byte-oriented; for decoding float/double
+ * information, the bit values are converted (not cast) into a long type. Note
+ * that long values are used throughout even though most may be cast to ints;
+ * this is primarily to avoid having to worry about signed values, even if it
+ * would be more efficient to do so.
+ *
+ * There are a number of standard codecs ({@link #UDELTA5}, {@link #UNSIGNED5},
+ * {@link #BYTE1}, {@link #CHAR3}) that are used in the implementation of many
+ * bands; but there are a variety of other ones, and indeed the specification
+ * assumes that other combinations of values can result in more specific and
+ * efficient formats. There are also a sequence of canonical encodings defined
+ * by the Pack200 specification, which allow a codec to be referred to by
+ * canonical number. TODO Add links to canonical numbers when this has been
+ * done.
+ *
+ * @author Alex Blewitt
+ * @version $Revision: $
+ */
+public class Codec {
+ /**
+ * BCI5 = (5,4): Used for storing branching information in bytecode.
+ */
+ public static Codec BCI5 = new Codec(5, 4);
+
+ /**
+ * BRANCH5 = (5,4,2): Used for storing branching information in bytecode.
+ */
+ public static final Codec BRANCH5 = new Codec(5, 4, 2);
+
+ /**
+ * BYTE1 = (1,256): Used for storing plain bytes.
+ */
+ public static final Codec BYTE1 = new Codec(1, 256);
+
+ /**
+ * CHAR3 = (3,128): Used for storing text (UTF-8) strings. NB This isn't
+ * quite the same as UTF-8, but has similar properties; ASCII characters
+ * < 127 are stored in a single byte.
+ */
+ public static final Codec CHAR3 = new Codec(3, 128);
+
+ /**
+ * DELTA5 = (5,64,1,1): Used for the majority of numerical codings where
+ * there is a correlated sequence of signed values.
+ */
+ public static final Codec DELTA5 = new Codec(5, 64, 1, 1);
+
+ /**
+ * DELTA5 = (5,64,2,1): Used for the majority of numerical codings where
+ * there is a correlated sequence of signed values, but where most of them
+ * are expected to be non-negative.
+ */
+ public static final Codec MDELTA5 = new Codec(5, 64, 2, 1);
+
+ /**
+ * SIGNED5 = (5,64,1): Used for small signed values.
+ */
+ public static final Codec SIGNED5 = new Codec(5, 64, 1);
+
+ /**
+ * UDELTA5 = (5,64,0,1): Used for the majority of numerical codings where
+ * there is a correlated sequence of unsigned values.
+ */
+ public static final Codec UDELTA5 = new Codec(5, 64, 0, 1);
+
+ /**
+ * USIGNED5 = (5,64): Used for small unsigned values.
+ */
+ public static final Codec UNSIGNED5 = new Codec(5, 64);
+
+ /**
+ * The maximum number of bytes in each coding word
+ */
+ private int b;
+
+ /**
+ * Whether delta encoding is used (0=false,1=true)
+ */
+ private int d;
+
+ /**
+ * The radix of the encoding
+ */
+ private int h;
+
+ /**
+ * The co-parameter of h; h-256
+ */
+ private int l;
+
+ /**
+ * Represents signed numbers or not (0=unsigned,1/2=signed)
+ */
+ private int s;
+
+ /**
+ * Constructs an unsigned, non-delta Codec with the given B and H values.
+ *
+ * @param b
+ * the maximum number of bytes that a value can be encoded as
+ * [1..5]
+ * @param h
+ * the radix of the encoding [1..256]
+ */
+ public Codec(int b, int h) {
+ this(b, h, 0);
+ }
+
+ /**
+ * Constructs a non-delta Codec with the given B, H and S values.
+ *
+ * @param b
+ * the maximum number of bytes that a value can be encoded as
+ * [1..5]
+ * @param h
+ * the radix of the encoding [1..256]
+ * @param s
+ * whether the encoding represents signed numbers (s=0 is
+ * unsigned; s=1 is signed with 1s complement; s=2 is signed with ?)
+ */
+ public Codec(int b, int h, int s) {
+ this(b, h, s, 0);
+ }
+
+ /**
+ * Constructs a Codec with the given B, H, S and D values.
+ *
+ * @param b
+ * the maximum number of bytes that a value can be encoded as
+ * [1..5]
+ * @param h
+ * the radix of the encoding [1..256]
+ * @param s
+ * whether the encoding represents signed numbers (s=0 is
+ * unsigned; s=1 is signed with 1s complement; s=2 is signed with ?)
+ * @param d
+ * whether this is a delta encoding (d=0 is non-delta; d=1 is
+ * delta)
+ */
+ public Codec(int b, int h, int s, int d) {
+ if (b < 1 || b > 5)
+ throw new IllegalArgumentException("1<=b<=5");
+ if (h < 1 || h > 256)
+ throw new IllegalArgumentException("1<=h<=256");
+ if (s < 0 || s > 2)
+ throw new IllegalArgumentException("0<=s<=2");
+ if (d < 0 || d > 1)
+ throw new IllegalArgumentException("0<=d<=1");
+ if (b == 1 && h != 256)
+ throw new IllegalArgumentException("b=1 -> h=256");
+ if (h == 256 && b == 5)
+ throw new IllegalArgumentException("h=256 -> b!=5");
+ this.b = b;
+ this.h = h;
+ this.s = s;
+ this.d = d;
+ this.l = 256 - h;
+ }
+
+ /**
+ * Decode a sequence of bytes from the given input stream, returning the
+ * value as a long. Note that this method can only be applied for non-delta
+ * encodings.
+ *
+ * @param in
+ * the input stream to read from
+ * @return the value as a long
+ * @throws IOException
+ * if there is a problem reading from the underlying input
+ * stream
+ * @throws Pack200Exception
+ * if the encoding is a delta encoding
+ */
+ public long decode(InputStream in) throws IOException, Pack200Exception {
+ if (d != 0)
+ throw new Pack200Exception(
+ "Delta encoding used without passing in last value; this is a coding error");
+ return decode(in, 0);
+ }
+
+ /**
+ * Decode a sequence of bytes from the given input stream, returning the
+ * value as a long. If this encoding is a delta encoding (d=1) then the
+ * previous value must be passed in as a parameter. If it is a non-delta
+ * encoding, then it does not matter what value is passed in, so it makes
+ * sense for the value to be passed in by default using code similar to:
+ *
+ * <pre>
+ * long last = 0;
+ * while (condition) {
+ * last = codec.decode(in, last);
+ * // do something with last
+ * }
+ * </pre>
+ *
+ * TODO Note that s=2 encodings are not yet supported, and will result in an
+ * Error
+ *
+ * @param in
+ * the input stream to read from
+ * @param long
+ * the previous value read, which must be supplied if the codec
+ * is a delta encoding
+ * @return the value as a long
+ * @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(InputStream in, long last) throws IOException,
+ Pack200Exception {
+ int n = 0;
+ long z = 0;
+ long x;
+ do {
+ x = in.read();
+ if (x == -1)
+ throw new EOFException("End of stream reached whilst decoding");
+ z += x * Math.pow(h, n);
+ } while (++n < b && x >= l);
+ // process sign bit -- one's complement?
+ if (s == 1) {
+ if ((z & 1) == 1) {
+ z = z >>> 1 ^ -1L;
+ } else {
+ z >>>= 1;
+ }
+ } else if (s == 2) { // two's complement?
+ throw new Error("s==2 not yet implemented");
+ }
+ if (d == 1)
+ z += last;
+ return z;
+ }
+
+ /**
+ * Returns the codec in the form (1,256) or (1,64,1,1). Note that trailing
+ * zero fields are not shown.
+ */
+ 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(",");
+ buffer.append(s);
+ }
+ if (d != 0) {
+ buffer.append(",");
+ buffer.append(d);
+ }
+ buffer.append(')');
+ return buffer.toString();
+ }
+
+}
Propchange: incubator/harmony/enhanced/classlib/trunk/modules/archive/src/main/java/org/apache/harmony/archive/internal/pack200/Codec.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/harmony/enhanced/classlib/trunk/modules/archive/src/main/java/org/apache/harmony/archive/internal/pack200/Pack200Exception.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/archive/src/main/java/org/apache/harmony/archive/internal/pack200/Pack200Exception.java?rev=414164&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/archive/src/main/java/org/apache/harmony/archive/internal/pack200/Pack200Exception.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/archive/src/main/java/org/apache/harmony/archive/internal/pack200/Pack200Exception.java Wed Jun 14 02:24:18 2006
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2006 The Apache Software Foundation or its licensors,
+ * as applicable.
+ *
+ * Licensed 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;
+
+/**
+ * Represents a problem with a Pack200 coding/decoding issue.
+ *
+ * @author Alex Blewitt
+ * @version $Revision: $
+ */
+public class Pack200Exception extends Exception {
+
+ /**
+ * Create a new Pack200 exception with the given message and cause
+ *
+ * @param message
+ * the text message to display
+ */
+ public Pack200Exception(String message) {
+ super(message);
+ }
+
+ /**
+ * Create a new Pack200 exception with the given message and cause
+ *
+ * @param message
+ * the text message to display
+ * @param cause
+ * the throwable that caused this problem
+ */
+ public Pack200Exception(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Create a new Pack200 exception with the given message and cause
+ *
+ * @param cause
+ * the throwable that caused this problem
+ */
+ public Pack200Exception(Throwable cause) {
+ super(cause);
+ }
+
+}
Propchange: incubator/harmony/enhanced/classlib/trunk/modules/archive/src/main/java/org/apache/harmony/archive/internal/pack200/Pack200Exception.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/harmony/enhanced/classlib/trunk/modules/archive/src/main/java/org/apache/harmony/archive/internal/pack200/Segment.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/archive/src/main/java/org/apache/harmony/archive/internal/pack200/Segment.java?rev=414164&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/archive/src/main/java/org/apache/harmony/archive/internal/pack200/Segment.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/archive/src/main/java/org/apache/harmony/archive/internal/pack200/Segment.java Wed Jun 14 02:24:18 2006
@@ -0,0 +1,794 @@
+/*
+ * Copyright 2006 The Apache Software Foundation or its licensors,
+ * as applicable.
+ *
+ * Licensed 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;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.zip.GZIPInputStream;
+
+/**
+ * A Pack200 archive consists of one (or more) segments. Each segment is
+ * standalone, in the sense that every segment has the magic number header;
+ * thus, every segment is also a valid archive. However, it is possible to
+ * combine (non-GZipped) archives into a single large archive by concatenation
+ * alone. Thus all the hard work in unpacking an archive falls to understanding
+ * a segment.
+ *
+ * This class implements the Pack200 specification by an entry point ({@link #parse(InputStream)})
+ * which in turn delegates to a variety of other parse methods. Each parse
+ * method corresponds (roughly) to the name of the bands in the Pack200
+ * specification.
+ *
+ * The first component of a segment is the header; this contains (amongst other
+ * things) the expected counts of constant pool entries, which in turn defines
+ * how many values need to be read from the stream. Because values are variable
+ * width (see {@link Codec}), it is not possible to calculate the start of the
+ * next segment, although one of the header values does hint at the size of the
+ * segment if non-zero, which can be used for buffering purposes.
+ *
+ * Note that this does not perform any buffering of the input stream; each value
+ * will be read on a byte-by-byte basis. It does not perform GZip decompression
+ * automatically; both of these are expected to be done by the caller if the
+ * stream has the magic header for GZip streams ({@link GZIPInputStream#GZIP_MAGIC}).
+ * In any case, if GZip decompression is being performed the input stream will
+ * be buffered at a higher level, and thus this can read on a byte-oriented
+ * basis.
+ *
+ * @author Alex Blewitt
+ * @version $Revision: $
+ */
+public class Segment {
+ /**
+ * 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 };
+
+ /**
+ * Decode a segment from the given input stream. This does not attempt to
+ * re-assemble or export any class files, but it contains enough information
+ * to be able to re-assemble class files by external callers.
+ *
+ * @param in
+ * the input stream to read from TODO At this point, this must be
+ * a non-GZipped input stream, but this decoding could be done in
+ * this method in the future (but perhaps more likely on an
+ * archive as a whole)
+ * @return a segment parsed from the input stream
+ * @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 static Segment parse(InputStream in) throws IOException,
+ Pack200Exception {
+ Segment segment = new Segment();
+ segment.parseSegment(in);
+ return segment;
+ }
+
+ /**
+ * 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;
+ }
+ }
+
+ private long archiveModtime;
+
+ private long archiveSize;
+
+ private int attributeDefinitionCount;
+
+ private byte[] attributeDefinitionHeader;
+
+ private String[] attributeDefinitionLayout;
+
+ private String[] attributeDefinitionName;
+
+ private byte[] bandHeadersData;
+
+ private int bandHeadersSize;
+
+ private int classCount;
+
+ private String[] cpClass;
+
+ private int cpClassCount;
+
+ private String[] cpDescriptor;
+
+ private int cpDescriptorCount;
+
+ private double[] cpDouble;
+
+ private int cpDoubleCount;
+
+ private String[] cpFieldClass;
+
+ private int cpFieldCount;
+
+ private Object cpFieldDescriptor;
+
+ private float[] cpFloat;
+
+ private int cpFloatCount;
+
+ private String[] cpIMethodClass;
+
+ private int cpIMethodCount;
+
+ private String[] cpIMethodDescriptor;
+
+ private int[] cpInt;
+
+ private int cpIntCount;
+
+ private long[] cpLong;
+
+ private int cpLongCount;
+
+ private String[] cpMethodClass;
+
+ private int cpMethodCount;
+
+ private String[] cpMethodDescriptor;
+
+ private String[] cpSignature;
+
+ private int cpSignatureCount;
+
+ private String[] cpString;
+
+ private int cpStringCount;
+
+ private String[] cpUTF8;
+
+ private int cpUTF8Count;
+
+ private int defaultClassMajorVersion;
+
+ private int defaultClassMinorVersion;
+
+ private int innerClassCount;
+
+ private int major;
+
+ private int minor;
+
+ private int numberOfFiles;
+
+ private SegmentOptions options;
+
+ private int segmentsRemaining;
+
+ public long getArchiveModtime() {
+ return archiveModtime;
+ }
+
+ public long getArchiveSize() {
+ return archiveSize;
+ }
+
+ public int getNumberOfFiles() {
+ return numberOfFiles;
+ }
+
+ private SegmentOptions getOptions() {
+ return options;
+ }
+
+ public int getSegmentsRemaining() {
+ return segmentsRemaining;
+ }
+
+ private void parseArchiveFileCounts(InputStream in) throws IOException,
+ Pack200Exception {
+ if (getOptions().hasArchiveFileCounts()) {
+ setArchiveSize(Codec.UNSIGNED5.decode(in) << 32
+ | Codec.UNSIGNED5.decode(in));
+ setSegmentsRemaining(Codec.UNSIGNED5.decode(in));
+ setArchiveModtime(Codec.UNSIGNED5.decode(in));
+ setNumberOfFiles(Codec.UNSIGNED5.decode(in));
+ }
+ }
+
+ private void parseArchiveSpecialCounts(InputStream in) throws IOException,
+ Pack200Exception {
+ if (getOptions().hasSpecialFormats()) {
+ setBandHeadersSize(Codec.UNSIGNED5.decode(in));
+ setAttributeDefinitionCount(Codec.UNSIGNED5.decode(in));
+ }
+ }
+
+ /**
+ * 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 = new byte[attributeDefinitionCount];
+ for (int i = 0; i < attributeDefinitionCount; i++) {
+ attributeDefinitionHeader[i] = (byte) Codec.BYTE1.decode(in);
+ }
+ attributeDefinitionName = parseReferences(in, Codec.UNSIGNED5,
+ attributeDefinitionCount, cpUTF8);
+ attributeDefinitionLayout = parseReferences(in, Codec.UNSIGNED5,
+ attributeDefinitionCount, cpUTF8);
+ if (attributeDefinitionCount > 0)
+ throw new Error("No idea what the adc is for yet");
+ }
+
+ private void parseClassCounts(InputStream in) throws IOException,
+ Pack200Exception {
+ setInnerClassCount(Codec.UNSIGNED5.decode(in));
+ setDefaultClassMinorVersion(Codec.UNSIGNED5.decode(in));
+ setDefaultClassMajorVersion(Codec.UNSIGNED5.decode(in));
+ setClassCount(Codec.UNSIGNED5.decode(in));
+ }
+
+ /**
+ * Parses the constant pool class names, using {@link #cpClassCount} to
+ * populate {@link #cpClass} from {@link #cpUTF8}.
+ *
+ * @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(in, Codec.UDELTA5, cpClassCount, cpUTF8);
+ }
+
+ private void parseCpCounts(InputStream in) throws IOException,
+ Pack200Exception {
+ setCPUtf8Count(Codec.UNSIGNED5.decode(in));
+ if (getOptions().hasCPNumberCounts()) {
+ setCPIntCount(Codec.UNSIGNED5.decode(in));
+ setCPFloatCount(Codec.UNSIGNED5.decode(in));
+ setCPLongCount(Codec.UNSIGNED5.decode(in));
+ setCPDoubleCount(Codec.UNSIGNED5.decode(in));
+ }
+ setCPStringCount(Codec.UNSIGNED5.decode(in));
+ setCPClassCount(Codec.UNSIGNED5.decode(in));
+ setCPSignatureCount(Codec.UNSIGNED5.decode(in));
+ setCPDescriptorCount(Codec.UNSIGNED5.decode(in));
+ setCPFieldCount(Codec.UNSIGNED5.decode(in));
+ setCPMethodCount(Codec.UNSIGNED5.decode(in));
+ setCPIMethodCount(Codec.UNSIGNED5.decode(in));
+ }
+
+ /**
+ * 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 <i>name:type</i>,
+ * largely to make it easier for representing field and method descriptors
+ * (e.g. <code>out:java.lang.PrintStream</code>) 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(in, Codec.DELTA5,
+ cpDescriptorCount, cpUTF8);
+ String[] cpDescriptorTypes = parseReferences(in, Codec.UDELTA5,
+ cpDescriptorCount, cpSignature);
+ cpDescriptor = new String[cpDescriptorCount];
+ for (int i = 0; i < cpDescriptorCount; i++) {
+ cpDescriptor[i] = cpDescriptorNames[i] + ":" + cpDescriptorTypes[i];
+ }
+ }
+
+ private void parseCpDouble(InputStream in) throws IOException,
+ Pack200Exception {
+ cpDouble = new double[cpDoubleCount];
+ long[] lastBits = new long[cpDoubleCount];
+ long last = 0;
+ for (int i = 0; i < cpDoubleCount; i++) {
+ last = Codec.UDELTA5.decode(in, last);
+ lastBits[i] = last << 32;
+ }
+ for (int i = 0; i < cpDoubleCount; i++) {
+ last = Codec.DELTA5.decode(in, last);
+ lastBits[i] = lastBits[i] | last;
+ cpDouble[i] = Double.longBitsToDouble(lastBits[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(in, Codec.DELTA5, cpFieldCount, cpClass);
+ cpFieldDescriptor = parseReferences(in, Codec.UDELTA5, cpFieldCount,
+ cpDescriptor);
+ }
+
+ private void parseCpFloat(InputStream in) throws IOException,
+ Pack200Exception {
+ cpFloat = new float[cpFloatCount];
+ long last = 0;
+ for (int i = 0; i < cpFloatCount; i++) {
+ last = Codec.UDELTA5.decode(in, last);
+ cpFloat[i] = Float.intBitsToFloat((int) last);
+ }
+ }
+
+ /**
+ * 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(in, Codec.DELTA5, cpIMethodCount,
+ cpClass);
+ cpIMethodDescriptor = parseReferences(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 = new long[cpLongCount];
+ long last = 0;
+ for (int i = 0; i < cpLongCount; i++) {
+ last = Codec.UDELTA5.decode(in, last);
+ cpLong[i] = last << 32;
+ }
+ for (int i = 0; i < cpLongCount; i++) {
+ last = Codec.DELTA5.decode(in, last);
+ cpLong[i] = cpLong[i] | last;
+ }
+ }
+
+ /**
+ * 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(in, Codec.DELTA5, cpMethodCount,
+ cpClass);
+ cpMethodDescriptor = parseReferences(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
+ * <code>public static void main(String args[])</code> has a form of
+ * <code>[L(V)</code> and a classes array of
+ * <code>[java.lang.String]</code>. The {@link #cpSignature} is a string
+ * represenation identical to the bytecode equivalent
+ * <code>[Ljava/lang/String;(V)</code> 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(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 {
+ cpUTF8 = new String[(int) cpUTF8Count];
+ cpUTF8[0] = "";
+ 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];
+ }
+ // initialise 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];
+ }
+ }
+ }
+
+ /**
+ * Helper method to parse <i>count</i> references from <code>in</code>,
+ * using <code>codec</code> to decode the values as indexes into
+ * <code>reference</code> (which is populated prior to this call). An
+ * exception is thrown if a decoded index falls outside the range
+ * [0..reference.length-1].
+ *
+ * @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(InputStream in, Codec codec, int count,
+ String[] reference) throws IOException, Pack200Exception {
+ String[] result = new String[count];
+ long last = 0;
+ for (int i = 0; i < count; i++) {
+ int index = (int) (last = codec.decode(in, last));
+ if (index < 0 || index > reference.length)
+ throw new Pack200Exception(
+ "Something has gone wrong during parsing references");
+ result[i] = reference[index];
+ }
+ return result;
+ }
+
+ /**
+ * 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 {
+ 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);
+ }
+
+ private void parseSegmentHeader(InputStream in) throws IOException,
+ Pack200Exception, Error, Pack200Exception {
+ for (int m = 0; m < magic.length; m++)
+ if (in.read() != magic[m])
+ throw new Error("Bad header");
+ setMinorVersion((int) Codec.UNSIGNED5.decode(in));
+ setMajorVersion((int) Codec.UNSIGNED5.decode(in));
+ setOptions(new SegmentOptions((int) Codec.UNSIGNED5.decode(in, 0)));
+ parseArchiveFileCounts(in);
+ parseArchiveSpecialCounts(in);
+ parseCpCounts(in);
+ parseClassCounts(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.bandHeadersData = 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;
+ }
+
+ /**
+ * 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 setMajorVersion(int version) throws Pack200Exception {
+ if (version != 150)
+ throw new Pack200Exception("Invalid segment major version");
+ major = 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 setMinorVersion(int version) throws Pack200Exception {
+ if (version != 7)
+ throw new Pack200Exception("Invalid segment minor version");
+ minor = version;
+ }
+
+ public void setNumberOfFiles(long value) {
+ numberOfFiles = (int) value;
+ }
+
+ private void setOptions(SegmentOptions options) {
+ this.options = options;
+ }
+
+ public void setSegmentsRemaining(long value) {
+ segmentsRemaining = (int) value;
+ }
+}
Propchange: incubator/harmony/enhanced/classlib/trunk/modules/archive/src/main/java/org/apache/harmony/archive/internal/pack200/Segment.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/harmony/enhanced/classlib/trunk/modules/archive/src/main/java/org/apache/harmony/archive/internal/pack200/SegmentOptions.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/archive/src/main/java/org/apache/harmony/archive/internal/pack200/SegmentOptions.java?rev=414164&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/archive/src/main/java/org/apache/harmony/archive/internal/pack200/SegmentOptions.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/archive/src/main/java/org/apache/harmony/archive/internal/pack200/SegmentOptions.java Wed Jun 14 02:24:18 2006
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2006 The Apache Software Foundation or its licensors,
+ * as applicable.
+ *
+ * Licensed 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;
+
+/**
+ * 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
+ * pull it out into a separate class, not least because methods can then be used
+ * to determine the semantic meaning of the flags. In languages with a
+ * pre-processor, these may be defined by macros that do bitflag manipulation
+ * instead.
+ *
+ * @author Alex Blewitt
+ * @version $Revision: $
+ */
+public class SegmentOptions {
+ private static final int DEFLATE_HINT = 1 << 5;
+
+ private static final int HAVE_ALL_CODE_FLAGS = 1 << 2;
+
+ private static final int HAVE_CLASS_FLAGS_HI = 1 << 9;
+
+ // private static final int UNUSED_3 = 2^3;
+
+ private static final int HAVE_CODE_FLAGS_HI = 1 << 10;
+
+ private static final int HAVE_CP_NUMBERS = 1 << 1;
+
+ private static final int HAVE_FIELD_FLAGS_HI = 1 << 10;
+
+ private static final int HAVE_FILE_HEADERS = 1 << 4;
+
+ private static final int HAVE_FILE_MODTIME = 1 << 6;
+
+ private static final int HAVE_FILE_OPTIONS = 1 << 7;
+
+ private static final int HAVE_FILE_SIZE_HI = 1 << 8;
+
+ private static final int HAVE_METHOD_FLAGS_HI = 1 << 11;
+
+ private static final int HAVE_SPECIAL_FORMATS = 1 << 0;
+
+ /**
+ * The bit flags that are defined as unused by the specification;
+ * specifically, every bit above bit 13 and bit 3.
+ */
+ private static final int UNUSED = -1 << 13 | 1 << 3;
+
+ private int options;
+
+ /**
+ * Creates a new segment options with the given integer value.
+ *
+ * @param options
+ * the integer value to use as the flags
+ * @throws Pack200Exception
+ * if an unused bit (bit 3 or bit 13+) is non-zero
+ */
+ public SegmentOptions(int options) throws Pack200Exception {
+ if ((options & UNUSED) != 0)
+ throw new Pack200Exception("Some unused flags are non-zero");
+ this.options = options;
+ }
+
+ public boolean hasAllCodeFlags() {
+ return (options & HAVE_ALL_CODE_FLAGS) != 0;
+ }
+
+ public boolean hasArchiveFileCounts() {
+ return (options & HAVE_FILE_HEADERS) != 0;
+ }
+
+ public boolean hasClassFlagsHi() {
+ return (options & HAVE_CLASS_FLAGS_HI) != 0;
+ }
+
+ public boolean hasCodeFlagsHi() {
+ return (options & HAVE_CODE_FLAGS_HI) != 0;
+ }
+
+ public boolean hasCPNumberCounts() {
+ return (options & HAVE_CP_NUMBERS) != 0;
+ }
+
+ public boolean hasFieldFlagsHi() {
+ return (options & HAVE_FIELD_FLAGS_HI) != 0;
+ }
+
+ public boolean hasFileModtime() {
+ return (options & HAVE_FILE_MODTIME) != 0;
+ }
+
+ public boolean hasFileOptions() {
+ return (options & HAVE_FILE_OPTIONS) != 0;
+ }
+
+ public boolean hasFileSizeHi() {
+ return (options & HAVE_FILE_SIZE_HI) != 0;
+ }
+
+ public boolean hasMethodFlagsHi() {
+ return (options & HAVE_METHOD_FLAGS_HI) != 0;
+ }
+
+ public boolean hasSpecialFormats() {
+ return (options & HAVE_SPECIAL_FORMATS) != 0;
+ }
+
+ public boolean shouldDeflate() {
+ return (options & DEFLATE_HINT) != 0;
+ }
+}
Propchange: incubator/harmony/enhanced/classlib/trunk/modules/archive/src/main/java/org/apache/harmony/archive/internal/pack200/SegmentOptions.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/internal/pack200/CodecTest.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/internal/pack200/CodecTest.java?rev=414164&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/internal/pack200/CodecTest.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/internal/pack200/CodecTest.java Wed Jun 14 02:24:18 2006
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2006 The Apache Software Foundation or its licensors,
+ * as applicable.
+ *
+ * Licensed 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.tests.internal.pack200;
+
+import java.io.ByteArrayInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+import org.apache.harmony.archive.internal.pack200.Codec;
+import org.apache.harmony.archive.internal.pack200.Pack200Exception;
+
+
+/**
+ * @author Alex Blewitt
+ * @version $Revision: $
+ */
+public class CodecTest extends TestCase {
+
+ public void testInvalidCodings() {
+ for (int i = 0; i < 256; i++) {
+ try {
+ new Codec(1, i);
+ fail("b=1 -> h=256");
+ } catch (IllegalArgumentException e) {
+ assertTrue(true);
+ }
+ }
+ for (int i = 1; i <= 5; i++) {
+ try {
+ new Codec(i, 256);
+ if (i == 5)
+ fail("h=256 -> b!=5");
+ } catch (IllegalArgumentException e) {
+ assertTrue(true);
+ }
+ }
+
+ }
+
+ public void testCodecToString() {
+ assertEquals("(1,256)", Codec.BYTE1.toString());
+ assertEquals("(3,128)", Codec.CHAR3.toString());
+ assertEquals("(5,4)", Codec.BCI5.toString());
+ assertEquals("(5,4,2)", Codec.BRANCH5.toString());
+ assertEquals("(5,64)", Codec.UNSIGNED5.toString());
+ assertEquals("(5,64,1)", Codec.SIGNED5.toString());
+ assertEquals("(5,64,0,1)", Codec.UDELTA5.toString());
+ assertEquals("(5,64,1,1)", Codec.DELTA5.toString());
+ assertEquals("(5,64,2,1)", Codec.MDELTA5.toString());
+ assertEquals("(5,64)", Codec.UNSIGNED5.toString());
+ assertEquals("(5,64,1)", Codec.SIGNED5.toString());
+ assertEquals("(5,64,1,1)", Codec.DELTA5.toString());
+ assertEquals("(5,64,2,1)", Codec.MDELTA5.toString());
+ }
+
+ public void testByte1() throws Exception {
+ for (int i = 0; i < 255; i++)
+ decode(Codec.BYTE1, new byte[] { (byte) i }, i, 0);
+ }
+
+ public void testByte1Delta() throws Exception {
+ Codec BYTE1D = new Codec(1, 256, 0, 1);
+ long last = 0;
+ for (int i = 1; i < 255; i++)
+ last = decode(BYTE1D, new byte[] { (byte) 1 }, i, last);
+ }
+
+ public void testByte1DeltaException() throws Exception {
+ Codec BYTE1D = new Codec(1, 256, 0, 1);
+ try {
+ BYTE1D.decode(new ByteArrayInputStream(new byte[] { (byte) 1 }));
+ fail("Decoding with a delta stream and not passing a last value should throw exception");
+ } catch (Pack200Exception e) {
+ assertTrue(true);
+ }
+ }
+
+ public void testUnsigned5() throws Exception {
+ decode(Codec.UNSIGNED5, new byte[] { 1 }, 1, 0);
+ decode(Codec.UNSIGNED5, new byte[] { (byte) 191 }, 191, 0);
+ decode(Codec.UNSIGNED5, new byte[] { (byte) 192, 0 }, 192, 0);
+ decode(Codec.UNSIGNED5, new byte[] { (byte) 193, 0 }, 193, 0);
+ decode(Codec.UNSIGNED5, new byte[] { (byte) 255, 0 }, 255, 0);
+ decode(Codec.UNSIGNED5, new byte[] { (byte) 192, 1 }, 256, 0);
+ decode(Codec.UNSIGNED5, new byte[] { (byte) 192, 5 }, 512, 0);
+ decode(Codec.UNSIGNED5, new byte[] { (byte) 192, 13 }, 1024, 0);
+ decode(Codec.UNSIGNED5, new byte[] { (byte) 192, 29 }, 2048, 0);
+ decode(Codec.UNSIGNED5, new byte[] { (byte) 255, (byte) 191 }, 12479, 0);
+
+ decode(Codec.UNSIGNED5, new byte[] { (byte) 192, (byte) 192, 0 },
+ 12480, 0);
+ decode(Codec.UNSIGNED5,
+ new byte[] { (byte) 255, (byte) 255, (byte) 191 }, 798911, 0);
+ decode(Codec.UNSIGNED5, new byte[] { (byte) 192, (byte) 192,
+ (byte) 192, 0 }, 798912, 0);
+ decode(Codec.UNSIGNED5, new byte[] { (byte) 255, (byte) 255,
+ (byte) 255, (byte) 191 }, 51130559, 0);
+ decode(Codec.UNSIGNED5, new byte[] { (byte) 192, (byte) 192,
+ (byte) 192, (byte) 192, 0 }, 51130560, 0);
+ decode(Codec.UNSIGNED5, new byte[] { (byte) 255, (byte) 252,
+ (byte) 252, (byte) 252, (byte) 252 }, 0xFFFFFFFFL, 0);
+ decodeFail(Codec.UNSIGNED5, new byte[] { (byte) 192 });
+ decodeFail(Codec.UNSIGNED5, new byte[] { (byte) 192, (byte) 192 });
+ decodeFail(Codec.UNSIGNED5, new byte[] { (byte) 192, (byte) 192,
+ (byte) 192 });
+ decodeFail(Codec.UNSIGNED5, new byte[] { (byte) 192, (byte) 192,
+ (byte) 192, (byte) 192 });
+ }
+
+ private void decodeFail(final Codec codec, final byte[] data)
+ throws IOException, Pack200Exception {
+ try {
+ decode(codec, data, 0, 0);
+ fail("Should have detected an EOFException");
+ } catch (EOFException e) {
+ assertTrue(true);
+ }
+ }
+
+ private long decode(final Codec codec, final byte[] data, final long value,
+ final long last) throws IOException, Pack200Exception {
+ final ByteArrayInputStream in = new ByteArrayInputStream(data);
+ assertEquals(value, codec.decode(in, last));
+ assertEquals(-1, in.read());
+ return (value);
+ }
+}
Propchange: incubator/harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/internal/pack200/CodecTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/internal/pack200/HelloWorld.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/internal/pack200/HelloWorld.java?rev=414164&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/internal/pack200/HelloWorld.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/internal/pack200/HelloWorld.java Wed Jun 14 02:24:18 2006
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2006 The Apache Software Foundation or its licensors,
+ * as applicable.
+ *
+ * Licensed 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.tests.internal.pack200;
+
+/**
+ * This is intended to be used as a test class for unpacking a packed Jar file.
+ * @author Alex Blewitt
+ * @version $Revision: $
+ */
+public class HelloWorld {
+ int i=97,j=42,k=12345;
+ float f=3.142f,g=2.718f;
+ long l=299792458;
+ double d=4.0d;
+ public static void main(String[] args) {
+ System.out.println("Hello world");
+ }
+ public HelloWorld[][] method(int a,int b,int c) {
+ return null;
+ }
+}
Propchange: incubator/harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/internal/pack200/HelloWorld.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/internal/pack200/HelloWorld.pack
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/internal/pack200/HelloWorld.pack?rev=414164&view=auto
==============================================================================
Binary file - no diff available.
Propchange: incubator/harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/internal/pack200/HelloWorld.pack
------------------------------------------------------------------------------
svn:mime-type = application/octet-stream
Added: incubator/harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/internal/pack200/SegmentOptionsTest.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/internal/pack200/SegmentOptionsTest.java?rev=414164&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/internal/pack200/SegmentOptionsTest.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/internal/pack200/SegmentOptionsTest.java Wed Jun 14 02:24:18 2006
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2006 The Apache Software Foundation or its licensors,
+ * as applicable.
+ *
+ * Licensed 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.tests.internal.pack200;
+
+import junit.framework.TestCase;
+
+import org.apache.harmony.archive.internal.pack200.Pack200Exception;
+import org.apache.harmony.archive.internal.pack200.SegmentOptions;
+
+/**
+ * @author Alex Blewitt
+ * @version $Revision: $
+ */
+public class SegmentOptionsTest extends TestCase {
+ public void testUnused() {
+ int[] unused = new int[] { 3, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
+ 23, 24, 25, 26, 27, 28, 29, 30, 31 };
+ for (int i = 0; i < unused.length; i++) {
+ try {
+ new SegmentOptions(1 << unused[i]);
+ fail("Bit " + unused[i] + " should be unused, but it's not caught during construction");
+ } catch (Pack200Exception e) {
+ assertTrue(true);
+ }
+ }
+ }
+}
Propchange: incubator/harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/internal/pack200/SegmentOptionsTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/internal/pack200/SegmentTest.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/internal/pack200/SegmentTest.java?rev=414164&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/internal/pack200/SegmentTest.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/internal/pack200/SegmentTest.java Wed Jun 14 02:24:18 2006
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2006 The Apache Software Foundation or its licensors,
+ * as applicable.
+ *
+ * Licensed 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.tests.internal.pack200;
+
+import org.apache.harmony.archive.internal.pack200.Segment;
+
+import junit.framework.TestCase;
+
+/**
+ * @author Alex Blewitt
+ * @version $Revision: $
+ */
+public class SegmentTest extends TestCase {
+ /**
+ * @param args
+ * @throws Exception
+ */
+ public void testHelloWorld() throws Exception {
+ assertNotNull(Segment.parse(Segment.class
+ .getResourceAsStream("/org/apache/harmony/archive/tests/internal/pack200/HelloWorld.pack")));
+ }
+
+}
Propchange: incubator/harmony/enhanced/classlib/trunk/modules/archive/src/test/java/org/apache/harmony/archive/tests/internal/pack200/SegmentTest.java
------------------------------------------------------------------------------
svn:eol-style = native