Subversion Repositories DevTools

Rev

Blame | Last modification | View Log | RSS feed

package com.erggroup.mass.ant.tasks.util;

import java.util.zip.*;

/**
 * Checksum calculator for a 16-bit CCITT CRC.
 * 
 * @author bivey
 */
public class CCITT implements Checksum
{
        protected long checksum;
        protected long length;
        private static final long poly = 0x1021;        // CCITT Generator polynomial (x16 + x12 +x5 +1)
        private static long[] table = new long[256]; // Lookup table for fast calculation
        static
        {
                // Initialise the lookup table
                long remainder;
                for( int dividend = 0; dividend < 256; dividend++ )
                {
                        remainder = (long)dividend;
                        remainder = reflect(remainder,8);
                        remainder <<= 8;
                        
                        for( int bit = 0; bit < 8; bit++ )
                        {
                                if ( (remainder & 0x8000) != 0 )
                                {
                                        remainder = ( remainder << 1 ) ^ poly;
                                }
                                else
                                {
                                        remainder = ( remainder << 1 );
                                }
                        }
                        remainder = reflect(remainder, 16);
                        table[dividend] = (remainder & 0xFFFF);
                }
        }
        
        public CCITT()
        {
                reset();
        }
        
        /* Returns the current checksum value.
         * 
         * @see java.util.zip.Checksum#getValue()
         */
        public long getValue()
        {
                return checksum & 0xFFFF;
        }
        
        /**
         * Returns the length of data used in calculating the checksum.
         * 
         * @return data length
         */
        public long getLength()
        {
                return length;
        }
        
        /* Resets the checksum to its initial value.
         * 
         * @see java.util.zip.Checksum#reset()
         */
        public void reset()
        {
                checksum = reflect(0, 16);
                length = 0;
        }
        
        /* Updates the current checksum with the specified array of bytes.
         * 
         * @see java.util.zip.Checksum#update(byte[], int, int)
         */
        public void update(byte[] b, int off, int len)
        {
                int count = off + len;
                for( int i = off; i < count; i++ )
                {
                        update(b[i]);
                }
        }
        
        /* Updates the current checksum with the specified byte.
         * 
         * @see java.util.zip.Checksum#update(int)
         */
        public void update(int b)
        {
                update((byte)(b & 0xFF));
        }
        
        /**
         * Updates the checksum with the specified byte.
         * 
         * @param b The byte
         */
        public void update(byte b)
        {
                int index = ((int)(checksum ^ b) & 0xff);
                checksum >>>= 8;
                checksum &= 0xFF;
                checksum ^= (table[index]);
        length++;
        }
        
    /**
     * Reflects a value by taking the least significant bits into account
     *
     * @param value The value which should be reflected
     * @param bits The number of bits to be reflected
     * @return The value with the bottom bits reflected.
     */
    private static long reflect(long value, int bits) {
        long temp = 0L;
        for( int i = 0; i < bits; i++ ) 
        {
            temp <<= 1L;
            temp |= (value & 1L);
            value >>>= 1L;
        }
        return (value << bits) | temp;
    }
}