001: /*
002: * @(#)MD5InputStream.java 0.3-2 18/06/1999
003: *
004: * This file is part of the HTTPClient package
005: * Copyright (C) 1996-1999 Ronald Tschalär
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2 of the License, or (at your option) any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this library; if not, write to the Free
019: * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
020: * MA 02111-1307, USA
021: *
022: * For questions, suggestions, bug-reports, enhancement-requests etc.
023: * I may be contacted at:
024: *
025: * ronald@innovation.ch
026: *
027: */
028:
029: package HTTPClient;
030:
031: import java.io.IOException;
032: import java.io.InputStream;
033: import java.io.FilterInputStream;
034: import java.net.ProtocolException;
035:
036: /**
037: * This class calculates a running md5 digest of the data read. When the
038: * stream is closed the calculated digest is passed to a HashVerifier which
039: * is expected to verify this digest and to throw an Exception if it fails.
040: *
041: * @version 0.3-2 18/06/1999
042: * @author Ronald Tschalär
043: */
044: class MD5InputStream extends FilterInputStream {
045: private HashVerifier verifier;
046: private MD5 md5;
047: private long rcvd = 0;
048: private boolean closed = false;
049:
050: /**
051: * @param is the input stream over which the md5 hash is to be calculated
052: * @param verifier the HashVerifier to invoke when the stream is closed
053: */
054: public MD5InputStream(InputStream is, HashVerifier verifier) {
055: super (is);
056: this .verifier = verifier;
057: md5 = new MD5();
058: }
059:
060: public synchronized int read() throws IOException {
061: int b = in.read();
062: if (b != -1)
063: md5.Update((byte) b);
064: else
065: real_close();
066:
067: rcvd++;
068: return b;
069: }
070:
071: public synchronized int read(byte[] buf, int off, int len)
072: throws IOException {
073: int num = in.read(buf, off, len);
074: if (num > 0)
075: md5.Update(buf, off, num);
076: else
077: real_close();
078:
079: rcvd += num;
080: return num;
081: }
082:
083: public synchronized long skip(long num) throws IOException {
084: byte[] tmp = new byte[(int) num];
085: int got = read(tmp, 0, (int) num);
086:
087: if (got > 0)
088: return (long) got;
089: else
090: return 0L;
091: }
092:
093: /**
094: * Close the stream and check the digest. If the stream has not been
095: * fully read then the rest of the data will first be read (and discarded)
096: * to complete the digest calculation.
097: *
098: * @exception IOException if the close()'ing the underlying stream throws
099: * an IOException, or if the expected digest and
100: * the calculated digest don't match.
101: */
102: public synchronized void close() throws IOException {
103: while (skip(10000) > 0)
104: ;
105: real_close();
106: }
107:
108: /**
109: * Close the stream and check the digest.
110: *
111: * @exception IOException if the close()'ing the underlying stream throws
112: * an IOException, or if the expected digest and
113: * the calculated digest don't match.
114: */
115: private void real_close() throws IOException {
116: if (closed)
117: return;
118: closed = true;
119:
120: in.close();
121: verifier.verifyHash(md5.Final(), rcvd);
122: }
123: }
|