/*
 * @(#)DigestInputStream.java	1.26 97/08/07
 * 
 * Copyright 1993-1997 Sun Microsystems, Inc. 901 San Antonio Road, 
 * Palo Alto, California, 94303, U.S.A.  All Rights Reserved.
 * 
 * This software is the confidential and proprietary information of Sun
 * Microsystems, Inc. ("Confidential Information").  You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with Sun.
 * 
 * CopyrightVersion 1.2
 * 
 */

package com.novell.java.security;

import java.io.IOException;
import java.io.EOFException;
import java.io.InputStream;
import java.io.FilterInputStream;
import java.io.PrintStream;
import java.io.ByteArrayInputStream;

/** 
 * Provides a transparent stream that updates the associated message
 * digest using the bits going through the stream. To complete the
 * message digest computation, call one of the digest methods on the
 * associated message digest after calling one of this digest input
 * stream's read() methods.
 *      
 * <p>It is possible to turn this stream on or off by calling the on()
 * method. When it is on, a call to read() results in an update on
 * the message digest. But when it is off, the message digest is not
 * updated. The default is for the stream to be on.
 *
 * <p>Note that digest objects can compute only one digest, so that
 * in order to compute intermediate digests, you should retain a handle
 * on the digest object and clone it for each digest to be computed,
 * leaving the orignal digest untouched.
 *
 * @see MessageDigest
 * @see DigestOutputStream
 *
 * @version 1.26 98/01/14
 * @author Benjamin Renaud 
 */

public class DigestInputStream extends FilterInputStream {

    /* NOTE: This should be made a generic UpdaterInputStream */

    /* Are we on or off? */
    private boolean on = true;

    /**
     * @internal
     *
     * The message digest associated with this stream.
     */
    protected MessageDigest digest;

    /**
     * Creates a digest input stream using the specified input stream
     * and message digest.
     *
     * @param stream The input stream.
     *
     * @param digest The message digest to associate with this stream.
     */
    public DigestInputStream(InputStream stream, MessageDigest digest) {
	super(stream);
	setMessageDigest(digest);
    }

    /**
     * Returns the message digest associated with this stream.
     *
     * @return The message digest associated with this stream.
     */
    public MessageDigest getMessageDigest() {
	return digest;
    }    

    /**
     * Associates the specified message digest with this stream.
     *
     * @param digest The message digest to be associated with this
     *               stream.  
     */
    public void setMessageDigest(MessageDigest digest) {
	this.digest = digest;
    }

    /**
     * Reads a byte and updates the message digest if the digest
     * function is on. It reads a byte from the input stream,
     * blocking until the byte is actually read. If the digest
     * function is on, the read() method will then call the
     * update() method on the message digest associated with
     * this stream, passing it the byte that was read. 
     *
     * @return The byte that was read.
     *
     * @exception IOException Thrown if an I/O error occurs.
     * 
     * @see MessageDigest#update(byte) 
     */
    public int read() throws IOException {
	int ch = in.read();
	if (on && ch != -1) {
	    digest.update((byte)ch);
	}
	return ch;
    }

    /**
     * Reads into a byte array and updates the message digest if the
     * digest function is on.  It reads up to len bytes from the
     * input stream into the array b[], starting at offset off. This
     * read() method blocks until the data is actually read. If the
     * digest function is on, read() will then call the update()
     * method on the message digest associated with this stream,
     * passing it the data.
     *
     * @param b The array into which the data is read.
     *
     * @param off The starting offset into the byte array (b[])
     *            where the data should be placed.
     *
     * @param len The maximum number of bytes to be read from the
     *            input stream into the byte array (b[]), starting
     *            at offset off.
     *
     * @return The actual number of bytes read. This is less than 
     *         len if the end of the stream is reached prior to reading
     *         len bytes. A -1 is returned if no bytes were read because
     *         the end of the stream had already been reached when the
     *         call was made.
     *
     * @exception IOException Thrown if an I/O error occurs.
     * 
     * @see MessageDigest#update(byte[], int, int) 
     */
    public int read(byte[] b, int off, int len) throws IOException {
	int result = in.read(b, off, len);
	if (on && result != -1) {
	    digest.update(b, off, result);
	}
	return result;
    }

    /**
     * Turns the digest function ON (default) or OFF. When it is ON,
     * a call to read() results in an update on the message digest.
     * But when it is OFF, the message digest is not updated.
     *   
     * @param on A boolean set to TRUE to set the digest function ON,
     *           or false to turn the digest function off.
     */
    public void on(boolean on) {
	this.on = on;
    }
	
    /**
     * Prints a String representation of this digest input stream and
     * its associated message digest object.  
     */
     public String toString() {
	 return "[Digest Input Stream] " + digest.toString();
     }
}	


  

