/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.petra.io.delta;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* @author Connor McKay
*/
public class RollingChecksum {
public RollingChecksum(
ReadableByteChannel readableByteChannel, int blockLength)
throws IOException {
_blockLength = blockLength;
_byteChannelReader = new ByteChannelReader(
readableByteChannel, _blockLength * DeltaUtil.BUFFER_FACTOR);
generateWeakChecksum();
}
public int currentBlockLength() {
return Math.min(_byteChannelReader.remaining(), _blockLength);
}
/**
* Returns the first byte of data in the current block.
*/
public byte getFirstByte() {
return _byteChannelReader.get(0);
}
/**
* Returns the position of the start of the current block in the file.
*/
public int getPosition() {
return _filePosition;
}
public boolean hasNext() throws IOException {
_byteChannelReader.maybeRead(1);
if (_byteChannelReader.remaining() >= 1) {
return true;
}
else {
return false;
}
}
public void nextBlock() throws IOException {
_filePosition += _byteChannelReader.skip(_blockLength);
generateWeakChecksum();
}
public void nextByte() throws IOException {
int blockLength = currentBlockLength();
int x = _byteChannelReader.get();
_filePosition++;
_a -= x;
_b -= blockLength * x;
_byteChannelReader.maybeRead(_blockLength);
if (_byteChannelReader.remaining() >= _blockLength) {
x = _byteChannelReader.get(_blockLength - 1);
_a += x;
_b += _a;
}
}
/**
* Returns the strong checksum of the current block.
*/
public byte[] strongChecksum() {
ByteBuffer buffer = _byteChannelReader.getBuffer();
int oldPosition = buffer.position();
int oldLimit = buffer.limit();
buffer.limit(buffer.position() + currentBlockLength());
try {
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
messageDigest.update(buffer);
buffer.limit(oldLimit);
buffer.position(oldPosition);
return messageDigest.digest();
}
catch (NoSuchAlgorithmException nsae) {
throw new ExceptionInInitializerError(nsae);
}
}
/**
* Returns the weak checksum of the current block.
*/
public int weakChecksum() {
return (_a & 0xffff) | (_b << 16);
}
protected void generateWeakChecksum() throws IOException {
_byteChannelReader.maybeRead(_blockLength);
_a = 0;
_b = 0;
for (int i = 0; i < currentBlockLength(); i++) {
_a += _byteChannelReader.get(i);
_b += _a;
}
}
private int _a;
private int _b;
private final int _blockLength;
private final ByteChannelReader _byteChannelReader;
private int _filePosition;
}