/*
* This file is part of Fim - File Integrity Manager
*
* Copyright (C) 2017 Etienne Vrignaud
*
* Fim is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Fim 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Fim. If not, see <http://www.gnu.org/licenses/>.
*/
package org.fim.internal.hash;
import org.fim.command.exception.FimInternalError;
import org.fim.model.Context;
import org.fim.model.FileHash;
import org.fim.model.Range;
import java.nio.ByteBuffer;
import java.security.NoSuchAlgorithmException;
import static java.lang.Math.max;
public class FrontHasher implements Hasher {
private final BlockHasher smallBlockHasher;
private final BlockHasher mediumBlockHasher;
private final Hasher fullHasher;
public FrontHasher(Context context) throws NoSuchAlgorithmException {
this.smallBlockHasher = new SmallBlockHasher(context);
this.mediumBlockHasher = new MediumBlockHasher(context);
this.fullHasher = new FullHasher(context);
}
@Override
public boolean isActive() {
return smallBlockHasher.isActive() && mediumBlockHasher.isActive() && fullHasher.isActive();
}
@Override
public void reset(long fileSize) {
smallBlockHasher.reset(fileSize);
mediumBlockHasher.reset(fileSize);
fullHasher.reset(fileSize);
}
@Override
public Range getNextRange(long filePosition) {
Range nextSmallRange;
Range nextMediumRange;
Range nextFullRange;
if (fullHasher.isActive()) {
nextSmallRange = smallBlockHasher.getNextRange(filePosition);
nextMediumRange = mediumBlockHasher.getNextRange(filePosition);
nextFullRange = fullHasher.getNextRange(filePosition);
Range nextRange = nextFullRange.adjustToRange(nextSmallRange);
nextRange = nextRange.adjustToRange(nextMediumRange);
return nextRange;
} else if (smallBlockHasher.isActive() && mediumBlockHasher.isActive()) {
nextSmallRange = smallBlockHasher.getNextRange(filePosition);
nextMediumRange = mediumBlockHasher.getNextRange(filePosition);
if (nextSmallRange == null && nextMediumRange == null) {
return null;
}
if (nextSmallRange == null) {
return nextMediumRange;
}
if (nextMediumRange == null) {
return nextSmallRange;
}
if (nextSmallRange.getTo() <= nextMediumRange.getFrom()) {
// Next small block is before the next medium block
return nextSmallRange;
}
if (nextMediumRange.getTo() <= nextSmallRange.getFrom()) {
// Next medium block is before the next small block
return nextMediumRange;
}
return nextSmallRange.union(nextMediumRange);
} else if (smallBlockHasher.isActive()) {
nextSmallRange = smallBlockHasher.getNextRange(filePosition);
return nextSmallRange;
}
throw new FimInternalError(String.format("Fim is not working correctly. Unable to getNextRange for filePosition %d", filePosition));
}
@Override
public void update(long filePosition, ByteBuffer buffer) {
update(smallBlockHasher, filePosition, buffer);
update(mediumBlockHasher, filePosition, buffer);
update(fullHasher, filePosition, buffer);
}
private void update(Hasher hasher, long filePosition, ByteBuffer buffer) {
if (hasher.isActive()) {
int bufferPosition = buffer.position();
int bufferLimit = buffer.limit();
try {
hasher.update(filePosition, buffer);
} finally {
buffer.limit(bufferLimit);
buffer.position(bufferPosition);
}
}
}
@Override
public String getHash() {
throw new FimInternalError("Not implemented");
}
@Override
public long getBytesHashed() {
long bytesHashed =
max(smallBlockHasher.getBytesHashed(),
max(mediumBlockHasher.getBytesHashed(), fullHasher.getBytesHashed()));
return bytesHashed;
}
@Override
public long getTotalBytesHashed() {
long totalBytesHashed =
max(smallBlockHasher.getTotalBytesHashed(),
max(mediumBlockHasher.getTotalBytesHashed(), fullHasher.getTotalBytesHashed()));
return totalBytesHashed;
}
@Override
public long getInstantThroughput() {
long instantThroughput =
max(smallBlockHasher.getInstantThroughput(),
max(mediumBlockHasher.getInstantThroughput(), fullHasher.getInstantThroughput()));
return instantThroughput;
}
@Override
public boolean hashComplete() {
return smallBlockHasher.hashComplete() && mediumBlockHasher.hashComplete() && fullHasher.hashComplete();
}
public FileHash getFileHash() {
return new FileHash(smallBlockHasher.getHash(), mediumBlockHasher.getHash(), fullHasher.getHash());
}
protected Hasher getSmallBlockHasher() {
return smallBlockHasher;
}
protected Hasher getMediumBlockHasher() {
return mediumBlockHasher;
}
protected Hasher getFullHasher() {
return fullHasher;
}
}