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 &lt; L; all prior values
+ * must be &gt; 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
+	 * &lt; 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