001    /*
002     *                    BioJava development code
003     *
004     * This code may be freely distributed and modified under the
005     * terms of the GNU Lesser General Public Licence.  This should
006     * be distributed with the code.  If you do not have a copy,
007     * see:
008     *
009     *      http://www.gnu.org/copyleft/lesser.html
010     *
011     * Copyright for this code is held jointly by the individual
012     * authors.  These should be listed in @author doc comments.
013     *
014     * For more information on the BioJava project and its aims,
015     * or to join the biojava-l mailing list, visit the home page
016     * at:
017     *
018     *      http://www.biojava.org/
019     *
020     */
021    
022    package org.biojava3.core.util;
023    
024    import java.util.zip.Checksum;
025    
026    /**
027     * Utility class that calculates a CRC64 checksum on a stream of bytes. Code was
028     * based on some from BioPerl. Note that we use longs then cast them to avoid
029     * the lack of an unsigned int in Java. Longs are 64-bit but we are only using
030     * the bottom 32 bits. An int is 32-bit but encodes sign so we can get amusing
031     * results if we don't allow for this.
032     *
033     * @author Unknown. Copied from Expasy4J for convenience. See <a
034     *         href="http://dev.isb-sib.ch/projects/expasy4j/">http://dev.isb-sib.ch/projects/expasy4j/</a>
035     */
036    public class CRC64Checksum implements Checksum {
037            private static final long POLY64 = 0xD800000000000000L;
038    
039            private static final long[] crcTable = new long[256];
040    
041            private long crc;
042    
043            static {
044                    for (int i = 0; i < 256; ++i) {
045                            long part = i;
046                            for (int j = 0; j < 8; ++j)
047                                    part = ((part & 1) != 0) ? (part >>> 1) ^ POLY64 : (part >>> 1);
048                            crcTable[i] = part;
049                    }
050            }
051    
052            public void update(int b) {
053                    long low = crc >>> 8;
054                    long high = crcTable[(int) ((crc ^ b) & 0xFF)];
055                    crc = low ^ high;
056            }
057    
058            public void update(byte[] b, int offset, int length) {
059                    for (int i = offset; i < length; ++i)
060                            update(b[i]);
061            }
062    
063            public void update(String s) {
064                    // update(s.getBytes(), 0, s.length());
065                    int size = s.length();
066                    for (int i = 0; i < size; ++i)
067                            update(s.charAt(i));
068    
069            }
070    
071            public long getValue() {
072                    return crc;
073            }
074    
075            /**
076             * Returns a zero-padded 16 character wide string containing the current
077             * value of this checksum in uppercase hexadecimal format.
078             */
079            public String toString() {
080                    StringBuffer builder = new StringBuffer();
081                    builder.append(Long.toHexString(crc >>> 4));
082                    builder.append(Long.toHexString(crc & 0xF));
083                    for (int i = 16 - builder.length(); i > 0; --i)
084                            builder.insert(0, '0');
085                    return builder.toString().toUpperCase();
086            }
087    
088            public void reset() {
089                    crc = 0;
090            }
091    }