/** * This work was created by participants in the DataONE project, and is * jointly copyrighted by participating institutions in DataONE. For * more information on DataONE, see our web site at http://dataone.org. * * Copyright ${year} * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License 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. * * $Id$ */ package org.dataone.speedbagit; import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; import java.security.MessageDigest; import org.apache.commons.codec.binary.Hex; /** * A class that manages a stream of bytes to a BagIt archive. While the data * is transferred/streamed, the size and checksum are computed. */ public class SpeedStream extends FilterInputStream { // The object that holds the checksum state & performs checksumming private MessageDigest digest; // The number of bytes streamed private int size; /** * Constructs a new SpeedStream object * * @param in The stream t * @param sum A MessageDigest that is updated as the stream is streamed * */ public SpeedStream(InputStream in, MessageDigest sum) { super(in); this.digest = sum; this.size = 0; // Reset the MessageDigest's state this.digest.reset(); } /** * Reads a byte. Will block if no input is available. * * @return the byte read, or -1 if the end of the stream is reached. * @throws IOException if an I/O error has occurred */ public int read() throws IOException { int b = in.read(); if (b != -1) { this.digest.update((byte) b); this.size += 1; } return b; } /** * Reads into an array of bytes. If len is not zero, the method * blocks until some input is available; otherwise, no * bytes are read and 0 is returned. * * @param buf the buffer into which the data is read * @param off the start offset in the destination array b * @param len the maximum number of bytes read * @return the actual number of bytes read, or -1 if the end * of the stream is reached. * @throws NullPointerException If buf is null. * @throws IndexOutOfBoundsException If off is negative, * len is negative, or len is greater than * buf.length - off * @throws IOException if an I/O error has occurred */ public int read(byte[] buf, int off, int len) throws IOException { len = in.read(buf, off, len); if (len != -1) { this.digest.update(buf, off, len); this.size += len; } return len; } /** * Returns the number of bytes that were streamed * * @return The number of bytes streamed */ public int getSize() { return size; } /** * Returns the checksum of the stream. * * Converts checksum.digest (byte[]) to a String. Since this is a checksum, * it should take up minimal space in memory. * * @return The checksum of the streamed bytes */ public String getChecksum() { return Hex.encodeHexString(this.digest.digest()); } }