package freenet.crypt;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import freenet.support.Logger;
public class MultiHashInputStream extends FilterInputStream {
// Bit flags for generateHashes
private Digester[] digesters;
private long readBytes;
class Digester {
HashType hashType;
MessageDigest digest;
Digester(HashType hashType) throws NoSuchAlgorithmException {
this.hashType= hashType;
digest = hashType.get();
}
HashResult getResult() {
HashResult result = new HashResult(hashType, digest.digest());
hashType.recycle(digest);
digest = null;
return result;
}
}
public MultiHashInputStream(InputStream proxy, long generateHashes) {
super(proxy);
ArrayList<Digester> digesters = new ArrayList<Digester>();
for(HashType type : HashType.values()) {
if((generateHashes & type.bitmask) == type.bitmask) {
try {
digesters.add(new Digester(type));
} catch (NoSuchAlgorithmException e) {
Logger.error(this, "Algorithm not available: "+type);
}
}
}
this.digesters = digesters.toArray(new Digester[digesters.size()]);
}
@Override
public int read(byte[] buf, int off, int len) throws IOException {
int ret = in.read(buf, off, len);
if(ret <= 0) return ret;
for(Digester d : digesters)
d.digest.update(buf, off, ret);
readBytes += ret;
return ret;
}
@Override
public int read(byte[] buf) throws IOException {
return read(buf, 0, buf.length);
}
/** Slow, you should buffer the stream to avoid this! */
@Override
public int read() throws IOException {
int ret = in.read();
if(ret < 0) return ret;
byte[] b = new byte[] { (byte)ret };
for(Digester d : digesters)
d.digest.update(b, 0, 1);
readBytes++;
return ret;
}
@Override
public long skip(long length) throws IOException {
byte[] buf = new byte[(int)Math.min(32768, length)];
long skipped = 0;
while(length > 0) {
int x = read(buf, 0, (int)Math.min(buf.length, length));
if(x == -1) return skipped;
skipped += x;
length -= x;
}
return skipped;
}
public HashResult[] getResults() {
HashResult[] results = new HashResult[digesters.length];
for(int i=0;i<digesters.length;i++)
results[i] = digesters[i].getResult();
digesters = null;
return results;
}
public long getReadBytes() {
return readBytes;
}
}