1. /*
  2. * Copyright 2003-2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. package org.apache.tools.ant.types.selectors.modifiedselector;
  18. import java.io.File;
  19. import java.io.FileInputStream;
  20. import java.io.FileOutputStream;
  21. import java.security.DigestInputStream;
  22. import java.security.MessageDigest;
  23. import java.security.NoSuchAlgorithmException;
  24. import java.security.NoSuchProviderException;
  25. import org.apache.tools.ant.BuildException;
  26. /**
  27. * Computes a 'hashvalue' for the content of file using
  28. * java.security.MessageDigest.
  29. * Use of this algorithm doesn't require any additional nested <param>s.
  30. * Supported <param>s are:
  31. * <table>
  32. * <tr>
  33. * <th>name</th><th>values</th><th>description</th><th>required</th>
  34. * </tr>
  35. * <tr>
  36. * <td> algorithm.algorithm </td>
  37. * <td> MD5 | SHA (default provider) </td>
  38. * <td> name of the algorithm the provider should use </td>
  39. * <td> no, defaults to MD5 </td>
  40. * </tr>
  41. * <tr>
  42. * <td> algorithm.provider </td>
  43. * <td> </td>
  44. * <td> name of the provider to use </td>
  45. * <td> no, defaults to <i>null</i> </td>
  46. * </tr>
  47. * </table>
  48. *
  49. * @version 2003-09-13
  50. * @since Ant 1.6
  51. */
  52. public class DigestAlgorithm implements Algorithm {
  53. // ----- member variables -----
  54. /**
  55. * MessageDigest algorithm to be used.
  56. */
  57. private String algorithm = "MD5";
  58. /**
  59. * MessageDigest Algorithm provider
  60. */
  61. private String provider = null;
  62. /**
  63. * Message Digest instance
  64. */
  65. private MessageDigest messageDigest = null;
  66. /**
  67. * Size of the read buffer to use.
  68. */
  69. private int readBufferSize = 8 * 1024;
  70. // ----- Algorithm-Configuration -----
  71. /**
  72. * Specifies the algorithm to be used to compute the checksum.
  73. * Defaults to "MD5". Other popular algorithms like "SHA" may be used as well.
  74. * @param algorithm the digest algorithm to use
  75. */
  76. public void setAlgorithm(String algorithm) {
  77. this.algorithm = algorithm;
  78. }
  79. /**
  80. * Sets the MessageDigest algorithm provider to be used
  81. * to calculate the checksum.
  82. * @param provider provider to use
  83. */
  84. public void setProvider(String provider) {
  85. this.provider = provider;
  86. }
  87. /** Initialize the security message digest. */
  88. public void initMessageDigest() {
  89. if (messageDigest != null) {
  90. return;
  91. }
  92. if ((provider != null) && !"".equals(provider) && !"null".equals(provider)) {
  93. try {
  94. messageDigest = MessageDigest.getInstance(algorithm, provider);
  95. } catch (NoSuchAlgorithmException noalgo) {
  96. throw new BuildException(noalgo);
  97. } catch (NoSuchProviderException noprovider) {
  98. throw new BuildException(noprovider);
  99. }
  100. } else {
  101. try {
  102. messageDigest = MessageDigest.getInstance(algorithm);
  103. } catch (NoSuchAlgorithmException noalgo) {
  104. throw new BuildException(noalgo);
  105. }
  106. }
  107. }
  108. // ----- Logic -----
  109. /**
  110. * This algorithm doesn't need any configuration.
  111. * Therefore it's always valid.
  112. * @return <i>true</i> if all is ok, otherwise <i>false</i>.
  113. */
  114. public boolean isValid() {
  115. return true;
  116. }
  117. /**
  118. * Computes a value for a file content with the specified digest algorithm.
  119. * @param file File object for which the value should be evaluated.
  120. * @return The value for that file
  121. */
  122. // implementation adapted from ...taskdefs.Checksum, thanks to Magesh for hint
  123. public String getValue(File file) {
  124. initMessageDigest();
  125. String checksum = null;
  126. try {
  127. if (!file.canRead()) {
  128. return null;
  129. }
  130. FileInputStream fis = null;
  131. FileOutputStream fos = null;
  132. byte[] buf = new byte[readBufferSize];
  133. try {
  134. messageDigest.reset();
  135. fis = new FileInputStream(file);
  136. DigestInputStream dis = new DigestInputStream(fis,
  137. messageDigest);
  138. while (dis.read(buf, 0, readBufferSize) != -1) {
  139. // do nothing
  140. }
  141. dis.close();
  142. fis.close();
  143. fis = null;
  144. byte[] fileDigest = messageDigest.digest();
  145. StringBuffer checksumSb = new StringBuffer();
  146. for (int i = 0; i < fileDigest.length; i++) {
  147. String hexStr = Integer.toHexString(0x00ff & fileDigest[i]);
  148. if (hexStr.length() < 2) {
  149. checksumSb.append("0");
  150. }
  151. checksumSb.append(hexStr);
  152. }
  153. checksum = checksumSb.toString();
  154. } catch (Exception e) {
  155. return null;
  156. }
  157. } catch (Exception e) {
  158. return null;
  159. }
  160. return checksum;
  161. }
  162. /**
  163. * Override Object.toString().
  164. * @return some information about this algorithm.
  165. */
  166. public String toString() {
  167. StringBuffer buf = new StringBuffer();
  168. buf.append("<DigestAlgorithm:");
  169. buf.append("algorithm=").append(algorithm);
  170. buf.append(";provider=").append(provider);
  171. buf.append(">");
  172. return buf.toString();
  173. }
  174. }