001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.eclipse.aether.util;
020
021import java.io.BufferedReader;
022import java.io.ByteArrayInputStream;
023import java.io.File;
024import java.io.FileInputStream;
025import java.io.IOException;
026import java.io.InputStream;
027import java.io.InputStreamReader;
028import java.nio.charset.StandardCharsets;
029import java.security.MessageDigest;
030import java.security.NoSuchAlgorithmException;
031import java.util.Collection;
032import java.util.LinkedHashMap;
033import java.util.Map;
034
035/**
036 * A utility class to assist in the verification and generation of checksums.
037 *
038 * @deprecated The use of class should be avoided, see {@link StringDigestUtil} and file processor in SPI module.
039 */
040@Deprecated
041public final class ChecksumUtils {
042
043    private ChecksumUtils() {
044        // hide constructor
045    }
046
047    /**
048     * Extracts the checksum from the specified file.
049     *
050     * @param checksumFile The path to the checksum file, must not be {@code null}.
051     * @return The checksum stored in the file, never {@code null}.
052     * @throws IOException If the checksum does not exist or could not be read for other reasons.
053     * @deprecated Use SPI FileProcessor to read and write checksum files.
054     */
055    @Deprecated
056    public static String read(File checksumFile) throws IOException {
057        String checksum = "";
058        try (BufferedReader br = new BufferedReader(
059                new InputStreamReader(new FileInputStream(checksumFile), StandardCharsets.UTF_8), 512)) {
060            while (true) {
061                String line = br.readLine();
062                if (line == null) {
063                    break;
064                }
065                line = line.trim();
066                if (!line.isEmpty()) {
067                    checksum = line;
068                    break;
069                }
070            }
071        }
072
073        if (checksum.matches(".+= [0-9A-Fa-f]+")) {
074            int lastSpacePos = checksum.lastIndexOf(' ');
075            checksum = checksum.substring(lastSpacePos + 1);
076        } else {
077            int spacePos = checksum.indexOf(' ');
078
079            if (spacePos != -1) {
080                checksum = checksum.substring(0, spacePos);
081            }
082        }
083
084        return checksum;
085    }
086
087    /**
088     * Calculates checksums for the specified file.
089     *
090     * @param dataFile The file for which to calculate checksums, must not be {@code null}.
091     * @param algos The names of checksum algorithms (cf. {@link MessageDigest#getInstance(String)} to use, must not be
092     *            {@code null}.
093     * @return The calculated checksums, indexed by algorithm name, or the exception that occurred while trying to
094     *         calculate it, never {@code null}.
095     * @throws IOException If the data file could not be read.
096     * @deprecated Use SPI checksum selector instead.
097     */
098    @Deprecated
099    public static Map<String, Object> calc(File dataFile, Collection<String> algos) throws IOException {
100        return calc(new FileInputStream(dataFile), algos);
101    }
102
103    /**
104     * @deprecated Use SPI checksum selector instead.
105     */
106    @Deprecated
107    public static Map<String, Object> calc(byte[] dataBytes, Collection<String> algos) throws IOException {
108        return calc(new ByteArrayInputStream(dataBytes), algos);
109    }
110
111    private static Map<String, Object> calc(InputStream data, Collection<String> algos) throws IOException {
112        Map<String, Object> results = new LinkedHashMap<>();
113
114        Map<String, MessageDigest> digests = new LinkedHashMap<>();
115        for (String algo : algos) {
116            try {
117                digests.put(algo, MessageDigest.getInstance(algo));
118            } catch (NoSuchAlgorithmException e) {
119                results.put(algo, e);
120            }
121        }
122
123        try (InputStream in = data) {
124            for (byte[] buffer = new byte[32 * 1024]; ; ) {
125                int read = in.read(buffer);
126                if (read < 0) {
127                    break;
128                }
129                for (MessageDigest digest : digests.values()) {
130                    digest.update(buffer, 0, read);
131                }
132            }
133        }
134
135        for (Map.Entry<String, MessageDigest> entry : digests.entrySet()) {
136            byte[] bytes = entry.getValue().digest();
137
138            results.put(entry.getKey(), toHexString(bytes));
139        }
140
141        return results;
142    }
143
144    /**
145     * Creates a hexadecimal representation of the specified bytes. Each byte is converted into a two-digit hex number
146     * and appended to the result with no separator between consecutive bytes.
147     *
148     * @param bytes The bytes to represent in hex notation, may be be {@code null}.
149     * @return The hexadecimal representation of the input or {@code null} if the input was {@code null}.
150     */
151    @SuppressWarnings("checkstyle:magicnumber")
152    public static String toHexString(byte[] bytes) {
153        return StringDigestUtil.toHexString(bytes);
154    }
155
156    /**
157     * Creates a byte array out of hexadecimal representation of the specified bytes. If input string is {@code null},
158     * {@code null} is returned. Input value must have even length (due hex encoding = 2 chars one byte).
159     *
160     * @param hexString The hexString to convert to byte array, may be {@code null}.
161     * @return The byte array of the input or {@code null} if the input was {@code null}.
162     * @since 1.8.0
163     */
164    @SuppressWarnings("checkstyle:magicnumber")
165    public static byte[] fromHexString(String hexString) {
166        return StringDigestUtil.fromHexString(hexString);
167    }
168}