/* * Copyright 2013-2015 EMC Corporation. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. * A copy of the License is located at * * http://www.apache.org/licenses/LICENSE-2.0.txt * * or in the "license" file accompanying this file. This file is distributed * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the License for the specific language governing * permissions and limitations under the License. */ package com.emc.ecs.sync.util; import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; import java.security.DigestInputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; /** * InputStream wrapper that counts the number of bytes that have been read and (optionally) calculates a checksum on the * data */ public class EnhancedInputStream extends FilterInputStream { public static final int UNSIZED = -1; protected static MessageDigest createMd5Digest() { try { return MessageDigest.getInstance("md5"); } catch (NoSuchAlgorithmException e) { throw new RuntimeException("Could not initialize MD5", e); } } private long size; private boolean closed = false; private long bytesRead = 0; public EnhancedInputStream(InputStream in) { this(in, UNSIZED, false); } public EnhancedInputStream(InputStream in, long size) { this(in, size, false); } public EnhancedInputStream(InputStream in, boolean calculateMd5) { this(in, UNSIZED, calculateMd5); } public EnhancedInputStream(InputStream in, long size, boolean calculateMd5) { super(calculateMd5 ? new DigestInputStream(in, createMd5Digest()) : in); this.size = size; } @Override public int read(byte[] b) throws IOException { return read(b, 0, b.length); } @Override public int read(byte[] b, int off, int len) throws IOException { int c = super.read(b, off, len); if(c != -1) { bytesRead += c; } return c; } @Override public int read() throws IOException { int v = super.read(); if (v != -1) bytesRead++; return v; } @Override public void close() throws IOException { super.close(); closed = true; } public long getSize() { return size; } public boolean isClosed() { return closed; } /** * @return the total number of bytes read */ public long getBytesRead() { return bytesRead; } public byte[] getMd5Digest() { if (!(in instanceof DigestInputStream)) throw new UnsupportedOperationException("MD5 checksum is not enabled"); if (!closed) throw new UnsupportedOperationException("cannot get MD5 until stream is closed"); return ((DigestInputStream) in).getMessageDigest().digest(); } }