1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package java.security;
19
20import java.io.FilterOutputStream;
21import java.io.IOException;
22import java.io.OutputStream;
23
24/**
25 * {@code DigestOutputStream} is a {@code FilterOutputStream} which maintains an
26 * associated message digest.
27 */
28public class DigestOutputStream extends FilterOutputStream {
29
30    /**
31     * The message digest for this stream.
32     */
33    protected MessageDigest digest;
34
35    // Indicates whether digest functionality is on or off
36    private boolean isOn = true;
37
38    /**
39     * Constructs a new instance of this {@code DigestOutputStream}, using the
40     * given {@code stream} and the {@code digest}.
41     *
42     * @param stream
43     *            the output stream.
44     * @param digest
45     *            the message digest.
46     */
47    public DigestOutputStream(OutputStream stream, MessageDigest digest) {
48        super(stream);
49        this.digest = digest;
50    }
51
52    /**
53     * Returns the message digest for this stream.
54     *
55     * @return the message digest for this stream.
56     */
57    public MessageDigest getMessageDigest() {
58        return digest;
59    }
60
61    /**
62     * Sets the message digest which this stream will use.
63     *
64     * @param digest
65     *            the message digest which this stream will use.
66     */
67    public void setMessageDigest(MessageDigest digest) {
68        this.digest = digest;
69    }
70
71    /**
72     * Writes the specified {@code int} to the stream. Updates the digest if
73     * this function is {@link #on(boolean)}.
74     *
75     * @param b
76     *            the byte to be written.
77     * @throws IOException
78     *             if writing to the stream causes a {@code IOException}
79     */
80    @Override
81    public void write(int b) throws IOException {
82        // update digest only if digest functionality is on
83        if (isOn) {
84            digest.update((byte)b);
85        }
86        // write the byte
87        out.write(b);
88    }
89
90    /**
91     * Writes {@code len} bytes into the stream, starting from the specified
92     * offset. Updates the digest if this function is {@link #on(boolean)}.
93     *
94     * @param b
95     *            the buffer to write to.
96     * @param off
97     *            the index of the first byte in {@code b} to write.
98     * @param len
99     *            the number of bytes in {@code b} to write.
100     * @throws IOException
101     *             if writing to the stream causes an {@code IOException}.
102     */
103    @Override
104    public void write(byte[] b, int off, int len) throws IOException {
105        // update digest only if digest functionality is on
106        if (isOn) {
107            digest.update(b, off, len);
108        }
109        // write len bytes
110        out.write(b, off, len);
111    }
112
113    /**
114     * Enables or disables the digest function (default is on).
115     *
116     * @param on
117     *            {@code true} if the digest should be computed, {@code false}
118     *            otherwise.
119     * @see MessageDigest
120     */
121    public void on(boolean on) {
122        isOn = on;
123    }
124
125    /**
126     * Returns a string containing a concise, human-readable description of this
127     * {@code DigestOutputStream} including the digest.
128     *
129     * @return a printable representation for this {@code DigestOutputStream}.
130     */
131    @Override
132    public String toString() {
133        return super.toString() + ", " + digest.toString() +
134            (isOn ? ", is on" : ", is off");
135    }
136}
137