I would like to implement an OutputStream
that can produce MessageDigests
. Likewise, I already have an InputStream
implementation of it here, which works fine and extends FilterInputStream
.
The problem is this: if I'm extending FilterOutputStream
, the checksums don't match. If I use FileOutputStream
it works fine (although that is not the stream I'd like to be using, as I'd like it to be a bit more generic than that).
public class MultipleDigestOutputStream extends FilterOutputStream
{
public static final String[] DEFAULT_ALGORITHMS = { EncryptionConstants.ALGORITHM_MD5,
EncryptionConstants.ALGORITHM_SHA1 };
private Map<String, MessageDigest> digests = new LinkedHashMap<>();
private File file;
public MultipleDigestOutputStream(File file, OutputStream os)
throws NoSuchAlgorithmException, FileNotFoundException
{
this(file, os, DEFAULT_ALGORITHMS);
}
public MultipleDigestOutputStream(File file, OutputStream os, String[] algorithms)
throws NoSuchAlgorithmException, FileNotFoundException
{
// super(file); // If extending FileOutputStream
super(os);
this.file = file;
for (String algorithm : algorithms)
{
addAlgorithm(algorithm);
}
}
public void addAlgorithm(String algorithm)
throws NoSuchAlgorithmException
{
MessageDigest digest = MessageDigest.getInstance(algorithm);
digests.put(algorithm, digest);
}
public MessageDigest getMessageDigest(String algorithm)
{
return digests.get(algorithm);
}
public Map<String, MessageDigest> getDigests()
{
return digests;
}
public String getMessageDigestAsHexadecimalString(String algorithm)
{
return MessageDigestUtils.convertToHexadecimalString(getMessageDigest(algorithm));
}
public void setDigests(Map<String, MessageDigest> digests)
{
this.digests = digests;
}
@Override
public void write(int b)
throws IOException
{
super.write(b);
System.out.println("write(int b)");
for (Map.Entry entry : digests.entrySet())
{
int p = b & 0xFF;
byte b1 = (byte) p;
MessageDigest digest = (MessageDigest) entry.getValue();
digest.update(b1);
}
}
@Override
public void write(byte[] b)
throws IOException
{
super.write(b);
for (Map.Entry entry : digests.entrySet())
{
MessageDigest digest = (MessageDigest) entry.getValue();
digest.update(b);
}
}
@Override
public void write(byte[] b, int off, int len)
throws IOException
{
super.write(b, off, len);
for (Map.Entry entry : digests.entrySet())
{
MessageDigest digest = (MessageDigest) entry.getValue();
digest.update(b, off, len);
}
}
@Override
public void close()
throws IOException
{
super.close();
}
}
My test case (the asserted checksums have been checked with md5sum
and sha1sum
):
public class MultipleDigestOutputStreamTest
{
@Before
public void setUp()
throws Exception
{
File dir = new File("target/test-resources");
if (!dir.exists())
{
//noinspection ResultOfMethodCallIgnored
dir.mkdirs();
}
}
@Test
public void testWrite()
throws IOException,
NoSuchAlgorithmException
{
String s = "This is a test.";
File file = new File("target/test-resources/metadata.xml");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
MultipleDigestOutputStream mdos = new MultipleDigestOutputStream(file, baos);
mdos.write(s.getBytes());
mdos.flush();
final String md5 = mdos.getMessageDigestAsHexadecimalString("MD5");
final String sha1 = mdos.getMessageDigestAsHexadecimalString("SHA-1");
Assert.assertEquals("Incorrect MD5 sum!", "120ea8a25e5d487bf68b5f7096440019", md5);
Assert.assertEquals("Incorrect SHA-1 sum!", "afa6c8b3a2fae95785dc7d9685a57835d703ac88", sha1);
System.out.println("MD5: " + md5);
System.out.println("SHA1: " + sha1);
}
}
Could you please advise as to what could be the problem and how to fix it? Many thanks in advance!