001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018: package org.apache.ivy.util;
019:
020: import java.io.BufferedReader;
021: import java.io.File;
022: import java.io.FileInputStream;
023: import java.io.FileReader;
024: import java.io.IOException;
025: import java.io.InputStream;
026: import java.security.MessageDigest;
027: import java.security.NoSuchAlgorithmException;
028: import java.util.HashMap;
029: import java.util.Locale;
030: import java.util.Map;
031:
032: public final class ChecksumHelper {
033:
034: private static final int BUFFER_SIZE = 2048;
035: private static Map algorithms = new HashMap();
036: static {
037: algorithms.put("md5", "MD5");
038: algorithms.put("sha1", "SHA-1");
039: }
040:
041: /**
042: * Checks the checksum of the given file against the given checksumFile, and throws an
043: * IOException if the checksum is not compliant
044: *
045: * @param dest
046: * the file to test
047: * @param checksumFile
048: * the file containing the expected checksum
049: * @param algorithm
050: * the checksum algorithm to use
051: * @throws IOException
052: * if an IO problem occur whle reading files or if the checksum is not compliant
053: */
054: public static void check(File dest, File checksumFile,
055: String algorithm) throws IOException {
056: String csFileContent = FileUtil.readEntirely(
057: new BufferedReader(new FileReader(checksumFile)))
058: .trim().toLowerCase(Locale.US);
059: String expected;
060: int spaceIndex = csFileContent.indexOf(' ');
061: if (spaceIndex != -1) {
062: expected = csFileContent.substring(0, spaceIndex);
063: } else {
064: expected = csFileContent;
065: }
066:
067: String computed = computeAsString(dest, algorithm).trim()
068: .toLowerCase(Locale.US);
069: if (!expected.equals(computed)) {
070: throw new IOException("invalid " + algorithm
071: + ": expected=" + expected + " computed="
072: + computed);
073: }
074: }
075:
076: public static String computeAsString(File f, String algorithm)
077: throws IOException {
078: return byteArrayToHexString(compute(f, algorithm));
079: }
080:
081: private static byte[] compute(File f, String algorithm)
082: throws IOException {
083: InputStream is = new FileInputStream(f);
084:
085: try {
086: MessageDigest md = getMessageDigest(algorithm);
087: md.reset();
088:
089: byte[] buf = new byte[BUFFER_SIZE];
090: int len = 0;
091: while ((len = is.read(buf)) != -1) {
092: md.update(buf, 0, len);
093: }
094: return md.digest();
095: } finally {
096: is.close();
097: }
098: }
099:
100: private static MessageDigest getMessageDigest(String algorithm) {
101: String mdAlgorithm = (String) algorithms.get(algorithm);
102: if (mdAlgorithm == null) {
103: throw new IllegalArgumentException("unknown algorithm "
104: + algorithm);
105: }
106: try {
107: return MessageDigest.getInstance(mdAlgorithm);
108: } catch (NoSuchAlgorithmException e) {
109: throw new IllegalArgumentException("unknown algorithm "
110: + algorithm);
111: }
112: }
113:
114: // byte to hex string converter
115: private static final char[] CHARS = { '0', '1', '2', '3', '4', '5',
116: '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
117:
118: /**
119: * Convert a byte[] array to readable string format. This makes the "hex" readable!
120: *
121: * @return result String buffer in String format
122: * @param in
123: * byte[] buffer to convert to string format
124: */
125: public static String byteArrayToHexString(byte[] in) {
126: byte ch = 0x00;
127:
128: if (in == null || in.length <= 0) {
129: return null;
130: }
131:
132: StringBuffer out = new StringBuffer(in.length * 2);
133:
134: //CheckStyle:MagicNumber OFF
135: for (int i = 0; i < in.length; i++) {
136: ch = (byte) (in[i] & 0xF0); // Strip off high nibble
137: ch = (byte) (ch >>> 4); // shift the bits down
138: ch = (byte) (ch & 0x0F); // must do this is high order bit is on!
139:
140: out.append(CHARS[(int) ch]); // convert the nibble to a String Character
141: ch = (byte) (in[i] & 0x0F); // Strip off low nibble
142: out.append(CHARS[(int) ch]); // convert the nibble to a String Character
143: }
144: //CheckStyle:MagicNumber ON
145:
146: return out.toString();
147: }
148:
149: private ChecksumHelper() {
150: }
151: }
|