001package org.eclipse.aether.spi.connector.checksum;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *  http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import java.io.BufferedInputStream;
023import java.io.ByteArrayInputStream;
024import java.io.File;
025import java.io.IOException;
026import java.io.InputStream;
027import java.nio.ByteBuffer;
028import java.nio.file.Files;
029import java.util.LinkedHashMap;
030import java.util.List;
031import java.util.Map;
032
033/**
034 * Helper for checksum operations.
035 *
036 * @since 1.8.0
037 */
038public final class ChecksumAlgorithmHelper
039{
040    private ChecksumAlgorithmHelper()
041    {
042        // nop
043    }
044
045    /**
046     * Calculates checksums for specified data.
047     *
048     * @param data        The content for which to calculate checksums, must not be {@code null}.
049     * @param factories   The checksum algorithm factories to use, must not be {@code null}.
050     * @return The calculated checksums, indexed by algorithm name, or the exception that occurred while trying to
051     * calculate it, never {@code null}.
052     * @throws IOException In case of any problem.
053     */
054    public static Map<String, String> calculate( byte[] data, List<ChecksumAlgorithmFactory> factories )
055            throws IOException
056    {
057        try ( InputStream inputStream = new ByteArrayInputStream( data ) )
058        {
059            return calculate( inputStream, factories );
060        }
061    }
062
063    /**
064     * Calculates checksums for specified file.
065     *
066     * @param file        The file for which to calculate checksums, must not be {@code null}.
067     * @param factories   The checksum algorithm factories to use, must not be {@code null}.
068     * @return The calculated checksums, indexed by algorithm name, or the exception that occurred while trying to
069     * calculate it, never {@code null}.
070     * @throws IOException In case of any problem.
071     */
072    public static Map<String, String> calculate( File file, List<ChecksumAlgorithmFactory> factories )
073            throws IOException
074    {
075        try ( InputStream inputStream = new BufferedInputStream( Files.newInputStream( file.toPath() ) ) )
076        {
077            return calculate( inputStream, factories );
078        }
079    }
080
081    private static Map<String, String> calculate( InputStream inputStream, List<ChecksumAlgorithmFactory> factories )
082            throws IOException
083    {
084        LinkedHashMap<String, ChecksumAlgorithm> algorithms = new LinkedHashMap<>();
085        factories.forEach( f -> algorithms.put( f.getName(), f.getAlgorithm() ) );
086        final byte[] buffer = new byte[ 1024 * 32 ];
087        for ( ; ; )
088        {
089            int read = inputStream.read( buffer );
090            if ( read < 0 )
091            {
092                break;
093            }
094            for ( ChecksumAlgorithm checksumAlgorithm : algorithms.values() )
095            {
096                checksumAlgorithm.update( ByteBuffer.wrap( buffer, 0, read ) );
097            }
098        }
099        LinkedHashMap<String, String> result = new LinkedHashMap<>();
100        algorithms.forEach( ( k, v ) -> result.put( k, v.checksum() ) );
101        return result;
102    }
103}