package freenet.crypt;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.zip.CRC32;
import java.util.zip.Checksum;
import freenet.support.Fields;
import freenet.support.io.FileUtil;
public class CRCChecksumChecker extends ChecksumChecker {
@Override
public int checksumLength() {
return 4;
}
@Override
public OutputStream checksumWriter(OutputStream os, int prefix) {
return new ChecksumOutputStream(os, new CRC32(), true, prefix);
}
@Override
public boolean checkChecksum(byte[] data, int offset, int length, byte[] checksum) {
if(checksum.length != 4) throw new IllegalArgumentException();
CRC32 crc = new CRC32();
crc.update(data, offset, length);
int computed = (int)crc.getValue();
int stored = Fields.bytesToInt(checksum);
return computed == stored;
}
@Override
public byte[] appendChecksum(byte[] data) {
byte[] output = new byte[data.length+4];
System.arraycopy(data, 0, output, 0, data.length);
Checksum crc = new CRC32();
crc.update(data, 0, data.length);
byte[] checksum = Fields.intToBytes((int)crc.getValue());
System.arraycopy(checksum, 0, output, data.length, 4);
return output;
}
@Override
public byte[] generateChecksum(byte[] data, int offset, int length) {
Checksum crc = new CRC32();
crc.update(data, offset, length);
return Fields.intToBytes((int)crc.getValue());
}
@Override
public int getChecksumTypeID() {
return ChecksumChecker.CHECKSUM_CRC;
}
@Override
public void copyAndStripChecksum(InputStream is, OutputStream destination, long length) throws IOException, ChecksumFailedException {
// FIXME refactor via a base class for ChecksumOutputStream.
CRC32 crc = new CRC32();
long remaining = length;
byte[] buffer = new byte[FileUtil.BUFFER_SIZE];
int read = 0;
DataInputStream source = new DataInputStream(is);
while ((remaining == -1) || (remaining > 0)) {
read = source.read(buffer, 0, ((remaining > FileUtil.BUFFER_SIZE) || (remaining == -1)) ? FileUtil.BUFFER_SIZE : (int) remaining);
if (read == -1) {
if (length == -1) {
return;
}
throw new EOFException("stream reached eof");
}
if(read == 0) throw new IOException("stream returning 0 bytes");
if(read != 0)
crc.update(buffer, 0, read);
destination.write(buffer, 0, read);
if (remaining > 0)
remaining -= read;
}
byte[] checksum = new byte[checksumLength()];
source.readFully(checksum);
byte[] myChecksum = Fields.intToBytes((int)crc.getValue());
if(!Arrays.equals(checksum, myChecksum))
throw new ChecksumFailedException();
}
@Override
public void readAndChecksum(DataInput is, byte[] buf, int offset, int length)
throws IOException, ChecksumFailedException {
is.readFully(buf, offset, length);
byte[] checksum = new byte[checksumLength()];
is.readFully(checksum);
if(!checkChecksum(buf, offset, length, checksum)) {
Arrays.fill(buf, offset, offset+length, (byte)0);
throw new ChecksumFailedException();
}
}
}