View Javadoc
1   /*
2    * #%L
3    * Nuiton Utils
4    * %%
5    * Copyright (C) 2004 - 2010 CodeLutin
6    * %%
7    * This program is free software: you can redistribute it and/or modify
8    * it under the terms of the GNU Lesser General Public License as 
9    * published by the Free Software Foundation, either version 3 of the 
10   * License, or (at your option) any later version.
11   * 
12   * This program is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   * GNU General Lesser Public License for more details.
16   * 
17   * You should have received a copy of the GNU General Lesser Public 
18   * License along with this program.  If not, see
19   * <http://www.gnu.org/licenses/lgpl-3.0.html>.
20   * #L%
21   */
22  
23  package org.nuiton.util;
24  
25  import org.apache.commons.logging.Log;
26  import org.apache.commons.logging.LogFactory;
27  
28  import java.io.BufferedInputStream;
29  import java.io.ByteArrayInputStream;
30  import java.io.File;
31  import java.io.FileInputStream;
32  import java.io.IOException;
33  import java.io.InputStream;
34  import java.security.DigestInputStream;
35  import java.security.MessageDigest;
36  import java.security.NoSuchAlgorithmException;
37  
38  import static org.nuiton.i18n.I18n.t;
39  
40  /**
41   * MD5InputStream, a subclass of FilterInputStream implementing MD5
42   * functionality on a stream.
43   *
44   * @author Tony Chemit - chemit@codelutin.com
45   */
46  public class MD5InputStream extends DigestInputStream {
47  
48      /** Class logger. */
49      private static final Log log = LogFactory.getLog(MD5InputStream.class);
50  
51      protected static MessageDigest getMD5Digest() throws IllegalStateException {
52          try {
53              MessageDigest digest = MessageDigest.getInstance("MD5");
54              return digest;
55          } catch (NoSuchAlgorithmException e) {
56              if (log.isErrorEnabled()) {
57                  log.error(t("nuitonutil.error.could.not.find.MD5"), e);
58              }
59              throw new IllegalStateException(e);
60          }
61      }
62  
63      /**
64       * Compute the MD5 for the given {@code input}.
65       *
66       * <b>Note:</b> The the stream will be closed after calling the method
67       * even if something was wrong.
68       *
69       * @param input the stream to parse
70       * @return the MD5 hash for the given input stream
71       * @throws IOException if any pb while reading in stream or digest
72       */
73      public static byte[] hash(InputStream input) throws IOException {
74          MD5InputStream in = new MD5InputStream(input);
75          try {
76              while (in.read() != -1) {
77                  // read a caracter on stream
78              }
79  
80              byte[] result = in.hash();
81              return result;
82          } finally {
83              in.close();
84          }
85      }
86  
87  
88      /**
89       * Compute the MD5 for the given {@code input} file.
90       *
91       * @param input the File stream to parse
92       * @return the MD5 hash for the given input File
93       * @throws IOException if any pb while reading in stream or digest
94       */
95      public static byte[] hash(File input) throws IOException {
96          InputStream inputStream = new BufferedInputStream(new FileInputStream(input));
97          byte[] result;
98          try {
99              result = hash(inputStream);
100         } finally {
101             inputStream.close();
102         }
103         return result;
104     }
105 
106 
107     /**
108      * Compute the MD5 for the given {@code input} sring.
109      *
110      * @param input the stream to parse
111      * @return the MD5 hash for the given input String
112      * @throws IOException if any pb while reading in stream or digest
113      */
114     public static byte[] hash(String input) throws IOException {
115         byte[] result = hash(new ByteArrayInputStream(input.getBytes()));
116         return result;
117     }
118 
119     /** length of readed stream */
120     protected long streamLength;
121 
122     /**
123      * Creates a MD5InputStream
124      *
125      * @param in The input stream
126      */
127     public MD5InputStream(InputStream in) {
128         super(in, getMD5Digest());
129     }
130 
131     @Override
132     public int read() throws IOException {
133         int c = super.read();
134 
135         if (c == -1) {
136             return -1;
137         }
138         streamLength++;
139         return c;
140     }
141 
142     @Override
143     public int read(byte bytes[], int offset, int length) throws IOException {
144         int r;
145 
146         if ((r = super.read(bytes, offset, length)) == -1) {
147             return r;
148         }
149         streamLength += r;
150         return r;
151     }
152 
153     /**
154      * Returns array of bytes representing hash of the stream as finalized for
155      * the current state.
156      *
157      * @return hash
158      * @see MessageDigest#digest()
159      */
160     public byte[] hash() {
161         return getMessageDigest().digest();
162     }
163 
164     public long getStreamLength() {
165         return streamLength;
166     }
167 }
168