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 022package org.biojava.nbio.core.util; 023 024import 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 */ 036public 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 @Override 053 public void update(int b) { 054 long low = crc >>> 8; 055 long high = crcTable[(int) ((crc ^ b) & 0xFF)]; 056 crc = low ^ high; 057 } 058 059 /** 060 * Updates the CRC-64 checksum with the specified array of bytes. 061 * <br/> 062 * Note that BioJava before version 6.0 implemented this method incorrectly, 063 * using {@code length} as an index. 064 * 065 * @throws IllegalArgumentException 066 * if {@code offset} is negative, or {@code length} is negative, or 067 * {@code offset+length} is negative or greater than the length of 068 * the array {@code b}. 069 */ 070 @Override 071 public void update(byte[] b, int offset, int length) { 072 if (b == null) { 073 throw new IllegalArgumentException("byte array cannot be null"); 074 } 075 if (offset < 0 || length < 0 || offset > b.length - length) { 076 throw new IllegalArgumentException("Offset and length must be non-negative"+ 077 " and their sum cannot be greater than length of byte array"); 078 } 079 for (int i = offset; i < length + offset; ++i) 080 update(b[i]); 081 } 082 083 public void update(String s) { 084 // update(s.getBytes(), 0, s.length()); 085 int size = s.length(); 086 for (int i = 0; i < size; ++i) 087 update(s.charAt(i)); 088 089 } 090 091 @Override 092 public long getValue() { 093 return crc; 094 } 095 096 /** 097 * Returns a zero-padded 16 character wide string containing the current 098 * value of this checksum in uppercase hexadecimal format. 099 */ 100 @Override 101 public String toString() { 102 StringBuffer builder = new StringBuffer(); 103 builder.append(Long.toHexString(crc >>> 4)); 104 builder.append(Long.toHexString(crc & 0xF)); 105 for (int i = 16 - builder.length(); i > 0; --i) 106 builder.insert(0, '0'); 107 return builder.toString().toUpperCase(); 108 } 109 110 @Override 111 public void reset() { 112 crc = 0; 113 } 114}