package freenet.crypt;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.zip.Checksum;
import freenet.support.Fields;
public class ChecksumOutputStream extends FilterOutputStream {
final Checksum crc;
private boolean closed;
private final boolean writeChecksum;
// FIXME unit test the skipping mechanism, or move it to another file?
private final int skipPrefix;
private int bytesInsidePrefix;
public ChecksumOutputStream(OutputStream out, final Checksum crc, boolean writeChecksum, int skipPrefix) {
super(out);
this.crc = crc;
this.writeChecksum = writeChecksum;
this.skipPrefix = skipPrefix;
}
@Override
public void write(int b) throws IOException {
if(bytesInsidePrefix >= skipPrefix) {
crc.update(b);
} else bytesInsidePrefix++;
out.write(b);
}
@Override
public void write(byte[] buf, int offset, int length) throws IOException {
int chop = Math.min(skipPrefix - bytesInsidePrefix, length);
if(chop <= 0) {
// Finished writing prefix. Count everything later.
crc.update(buf, offset, length);
out.write(buf, offset, length);
} else {
if(length - chop > 0) {
crc.update(buf, offset+chop, length-chop);
bytesInsidePrefix = skipPrefix;
} else {
bytesInsidePrefix += length;
}
out.write(buf, offset, length);
}
}
@Override
public void write(byte[] buf) throws IOException {
write(buf, 0, buf.length);
}
@Override
public void close() throws IOException {
if(writeChecksum) {
synchronized(this) {
if(closed) throw new IOException("Already closed");
closed = true;
}
out.write(Fields.intToBytes((int)crc.getValue()));
}
}
public long getValue() {
return crc.getValue();
}
}