/*
 * Copyright (c) 1995, 1996 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Permission to use, copy, modify, and distribute this software
 * and its documentation for NON-COMMERCIAL purposes and without
 * fee is hereby granted provided that this copyright notice
 * appears in all copies. Please refer to the file "copyright.html"
 * for further important copyright and licensing information.
 *
 * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
 * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
 * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
 */
/*
 * @(#)Adler32.java	1.1 96/02/23 David Connelly
 *
 * Copyright (c) 1996 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Permission to use, copy, modify, and distribute this software
 * and its documentation for NON-COMMERCIAL purposes and without
 * fee is hereby granted provided that this copyright notice
 * appears in all copies. Please refer to the file "copyright.html"
 * for further important copyright and licensing information.
 *
 * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
 * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
 * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
 */

public
class Adler32 implements Checksum {
    private int value = 1;
    private long count;

    /*
     * BASE is the largest prime number smaller than 65536
     * NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
     */
    private static final int BASE = 65521;
    private static final int NMAX = 5552;

    /**
     * Update current Adler-32 checksum given the specified byte.
     */
    public void update(int b) {
	int s1 = value & 0xffff;
	int s2 = (value >> 16) & 0xffff;
	s1 += b & 0xff;
	s2 += s1;
	value = ((s2 % BASE) << 16) | (s1 % BASE);
	count++;
    }

    /**
     * Update current Adler-32 checksum given the specified byte array.
     */
    public void update(byte b[], int off, int len) {
	int s1 = value & 0xffff;
	int s2 = (value >> 16) & 0xffff;

	while (len > 0) {
	    int k = len < NMAX ? len : NMAX;
	    len -= k;
	    while (k-- > 0) {
		s1 += b[off++] & 0xff;
		s2 += s1;
	    }
	    s1 %= BASE;
	    s2 %= BASE;
	}
	value = (s2 << 16) | s1;
	count += len;
    }

    /**
     * Reset Adler-32 checksum to initial value.
     */
    public void reset() {
	value = 1;
	count = 0;
    }

    /**
     * Returns current checksum value.
     */
    public long getValue() {
	return (long)value & 0xffffffff;
    }

    /**
     * Returns current byte count.
     */
    public long getCount() {
	return count;
    }
}
