Index: src/main/java/org/apache/harmony/pack200/BHSDCodec.java =================================================================== --- src/main/java/org/apache/harmony/pack200/BHSDCodec.java (revision 565676) +++ src/main/java/org/apache/harmony/pack200/BHSDCodec.java (working copy) @@ -55,6 +55,8 @@ * Represents signed numbers or not (0=unsigned,1/2=signed) */ private int s; + + private long cardinality; /** * Constructs an unsigned, non-delta Codec with the given B and H values. @@ -118,6 +120,11 @@ this.s = s; this.d = d; this.l = 256 - h; + if(h == 1) { + cardinality = b * 255 + 1; + } else { + cardinality = (long) ((long)(l * (1-Math.pow(h, b))/(1-h)) + Math.pow(h,b)); + } } /** @@ -127,11 +134,7 @@ * @return the cardinality of this codec */ public long cardinality() { - if (h > 1) { - return (long) (l * Math.pow(1 - h, b) / (1 - h) + Math.pow(h, b)); - } else { - return (b * 255) + 1; - } + return cardinality; } @@ -152,20 +155,28 @@ 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); - // This looks more complicated than it is - // When s=0, {1,2,3,4} is mapped to {1,2,3,4} - // When s=1, {1,2,3,4} is mapped to {-1,1,-2,2...} - // When s=2, {1,2,3,4} is mapped to {1,2,3,-1...} - if (isSigned()) { - int u = ((1 << s) - 1); - if ((z & u) == u) { - z = z >>> s ^ -1L; - } else { - z = z - (z >>> s); - } - } + z += x * Math.pow(h, n); + n++; + } while (n < b & isHigh(x)); + long u = z; + long twoPowS = (long)Math.pow(2, s); + double twoPowSMinusOne = twoPowS-1; + if(isSigned()) { + if(u % twoPowS < twoPowSMinusOne) { + if(cardinality < Math.pow(2, 32)) { + z = (long) (u - (Math.floor(u/ twoPowS))); + } else { + z = cast32((long) (u - (Math.floor(u/ twoPowS)))); + } + } else { + z = (long) (-Math.floor(u/ twoPowS) - 1); + } + } else { + // TODO: This is required in the spec, but it's making a test fail so needs more investigation. +// z = cast32(u); + } + + if (isDelta()) z += last; return z; @@ -171,7 +182,16 @@ return z; } - /** + private long cast32(long u) { + u = (long) ((long) ((u + Math.pow(2, 31)) % Math.pow(2, 32)) - Math.pow(2, 31)); + return u; + } + + private boolean isHigh(long x) { + return x>=l; + } + + /** * True if this encoding can code the given value * * @param value Index: src/main/java/org/apache/harmony/pack200/Codec.java =================================================================== --- src/main/java/org/apache/harmony/pack200/Codec.java (revision 572724) +++ src/main/java/org/apache/harmony/pack200/Codec.java (working copy) @@ -249,7 +249,7 @@ public long[] decode(int n, InputStream in, long firstValue) throws IOException, Pack200Exception { long result[] = new long[n + 1]; - long last = 0; + long last = firstValue; for(int i=1;i decodeScalar cpUTF8 = new String[cpUTF8Count]; cpUTF8[0] = ""; //$NON-NLS-1$ - int[] prefix = new int[cpUTF8Count]; int[] suffix = new int[cpUTF8Count]; - if (cpUTF8Count > 0) { - prefix[0] = 0; - suffix[0] = 0; - if (cpUTF8Count > 1) - prefix[1] = 0; - } long last = 0; - for (int i = 2; i < cpUTF8Count; i++) { - last = prefix[i] = (int) Codec.DELTA5.decode(in, last); - } + int[] prefix = decodeBandInt("cpUTF8Prefix", in, Codec.DELTA5, cpUTF8Count-2); int chars = 0; int bigSuffix = 0; for (int i = 1; i < cpUTF8Count; i++) { @@ -366,10 +352,10 @@ 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]) + cpUTF8[i] = lastString.substring(0, i>1 ? prefix[i-2] : 0) + new String(bigSuffixData[bigSuffix++]); } else { - cpUTF8[i] = lastString.substring(0, prefix[i]) + cpUTF8[i] = lastString.substring(0, i>1 ? prefix[i-2]: 0) + new String(data, chars, suffix[i]); chars += suffix[i]; } Index: src/main/java/org/apache/harmony/pack200/SegmentHeader.java =================================================================== --- src/main/java/org/apache/harmony/pack200/SegmentHeader.java (revision 572724) +++ src/main/java/org/apache/harmony/pack200/SegmentHeader.java (working copy) @@ -131,7 +131,7 @@ */ private void setArchiveMajorVersion(int version) throws Pack200Exception { if (version != 150) - throw new Pack200Exception("Invalid segment major version"); + throw new Pack200Exception("Invalid segment major version: " + version); archiveMajor = version; } @@ -354,8 +354,9 @@ */ private long decodeScalar(String name, InputStream in, BHSDCodec codec) throws IOException, Pack200Exception { -// debug("Parsed #" + name + " (1)"); - return codec.decode(in); + long ret = codec.decode(in); + debug("Parsed #" + name + " as " + ret); + return ret; } public void setArchiveModtime(long archiveModtime) { @@ -410,6 +411,12 @@ public int getBandHeadersSize() { return bandHeadersSize; } + + protected void debug(String message) { + if (System.getProperty("debug.pack200") != null) { + System.err.println(message); + } + } }