--- old/src/share/classes/java/util/zip/Adler32.java 2013-05-30 12:42:13.000000000 -0400 +++ new/src/share/classes/java/util/zip/Adler32.java 2013-05-30 12:42:12.000000000 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,8 +41,38 @@ */ public class Adler32 implements Checksum { + /* + * The Adler calculation is regarded as + * taking an input text T of length N = |T|, + * and computing two quantities, A(T) and B(T), + * where A(T) = 1 + sum_{0 <= i < |T|}(T_i) + * and B(T) = |T| + sum_{0 <= i < |T|}((|T| - i) * T_i), + * both modulo 65521. + * + * However, with sufficient algebraic manipulation, one can derive + * that A(U||V) = A(U) + A(V) - 1 + * and B(U||V) = B(U) + B(V) + |V| (A(U) - 1). + * + * This allows recursive subdivision, if that is considered desirable. + */ + + /** + * The modulo operation can be deferred for MAX_SLOP bytes of input, permitting + * faster byte-by-byte Adler computations. 1024 is plenty conservative. + */ + private final static int MAX_SLOP = 1024; + + /** + * For inputs smaller than JAVA_ADLER_BELOW JNI overheads make it faster + * to compute on the Java side. (This may change as overheads and compiler + * quality change). + */ + private final static int JAVA_ADLER_BELOW = 32; private int adler = 1; + private int aa = 1; + private int bb = 0; + private int slop = 0; /** * Creates a new Adler32 object. @@ -57,7 +87,13 @@ * @param b the byte to update the checksum with */ public void update(int b) { - adler = update(adler, b); + int la = aa + (b & 0xFF); + bb = bb + la; + aa = la; + slop++; + if (slop == MAX_SLOP) { + getValueI(); + } } /** @@ -70,7 +106,12 @@ if (off < 0 || len < 0 || off > b.length - len) { throw new ArrayIndexOutOfBoundsException(); } - adler = updateBytes(adler, b, off, len); + if (len < JAVA_ADLER_BELOW) { + for (int i = 0; i < len; i++) + update(b[i+off]); + } else { + setValue(updateBytes(getValueI(), b, off, len)); + } } /** @@ -79,10 +120,14 @@ * @param b the byte array to update the checksum with */ public void update(byte[] b) { - adler = updateBytes(adler, b, 0, b.length); + if (b.length < JAVA_ADLER_BELOW) { + for (int i = 0; i < b.length; i++) + update(b[i]); + } else { + setValue(updateBytes(getValueI(), b, 0, b.length)); + } } - /** * Updates the checksum with the bytes from the specified buffer. * @@ -104,13 +149,13 @@ if (rem <= 0) return; if (buffer instanceof DirectBuffer) { - adler = updateByteBuffer(adler, ((DirectBuffer)buffer).address(), pos, rem); + setValue(updateByteBuffer(getValueI(), ((DirectBuffer)buffer).address(), pos, rem)); } else if (buffer.hasArray()) { - adler = updateBytes(adler, buffer.array(), pos + buffer.arrayOffset(), rem); + setValue(updateBytes(getValueI(), buffer.array(), pos + buffer.arrayOffset(), rem)); } else { byte[] b = new byte[rem]; buffer.get(b); - adler = updateBytes(adler, b, 0, b.length); + setValue(updateBytes(getValueI(), b, 0, b.length)); } buffer.position(limit); } @@ -119,14 +164,34 @@ * Resets the checksum to initial value. */ public void reset() { + aa = 1; + bb = 0; adler = 1; + slop = 0; } /** * Returns the checksum value. */ public long getValue() { - return (long)adler & 0xffffffffL; + return getValueI() & 0xffffffffL; + } + + private int getValueI() { + if (slop > 0) { + aa = aa % 65521; + bb = bb % 65521; + adler = (bb << 16) + aa; + slop = 0; + } + return adler; + } + + private void setValue(int newValue) { + aa = newValue & 0xffff; + bb = newValue >>> 16; + adler = newValue; + slop = 0; } private native static int update(int adler, int b);