001/*
002 * ============================================================================
003 *  Copyright © 2002-2023 by Thomas Thrien.
004 *  All Rights Reserved.
005 * ============================================================================
006 *  Licensed to the public under the agreements of the GNU Lesser General Public
007 *  License, version 3.0 (the "License"). You may obtain a copy of the License at
008 *
009 *       http://www.gnu.org/licenses/lgpl.html
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, WITHOUT
013 *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
014 *  License for the specific language governing permissions and limitations
015 *  under the License.
016 */
017
018package org.tquadrat.foundation.util;
019
020import static java.util.Locale.ROOT;
021import static org.apiguardian.api.API.Status.STABLE;
022import static org.tquadrat.foundation.lang.CommonConstants.UTF8;
023import static org.tquadrat.foundation.lang.Objects.requireNonNullArgument;
024
025import java.io.File;
026import java.io.IOException;
027import java.io.Serializable;
028import java.math.BigInteger;
029import java.nio.charset.Charset;
030import java.nio.file.Path;
031import java.security.MessageDigest;
032import java.util.Arrays;
033import java.util.zip.Checksum;
034
035import org.apiguardian.api.API;
036import org.tquadrat.foundation.annotation.ClassVersion;
037import org.tquadrat.foundation.util.internal.HashImpl;
038
039/**
040 *  <p>{@summary The definition for a wrapper around hash values of any kind.}
041 *  These hashes are often used as checksums to validate the integrity of files
042 *  or messages.</p>
043 *
044 *  @version $Id: Hash.java 1052 2023-03-06 06:30:36Z tquadrat $
045 *  @extauthor Thomas Thrien - thomas.thrien@tquadrat.org
046 *  @UMLGraph.link
047 *  @since 0.1.1
048 */
049@SuppressWarnings( "NewClassNamingConvention" )
050@ClassVersion( sourceVersion = "$Id: Hash.java 1052 2023-03-06 06:30:36Z tquadrat $" )
051@API( status = STABLE, since = "0.1.1" )
052public sealed interface Hash extends Cloneable, Serializable
053    permits HashImpl
054{
055        /*---------*\
056    ====** Methods **==========================================================
057        \*---------*/
058    /**
059     *  Returns the hash as an array of bytes.
060     *
061     *  @return The hash value.
062     */
063    public byte [] bytes();
064
065    /**
066     *  Creates and returns a copy of this object.
067     *
068     *  @return The copy of this instance.
069     */
070    public Hash clone();
071
072    /**
073     *  Creates the hash for the given byte array, using the given algorithm.
074     *
075     *  @param  data    The input data.
076     *  @param  algorithm   The algorithm
077     *  @return A new instance of {@code Hash}.
078     */
079    public static Hash create( final byte [] data, final Checksum algorithm )
080    {
081        return HashImpl.create( data, algorithm );
082    }   //  create()
083
084    /**
085     *  Creates the hash for the given String, using the given algorithm.
086     *
087     *  @param  data    The input data.
088     *  @param  algorithm   The algorithm
089     *  @return A new instance of {@code Hash}.
090     */
091    public static Hash create( final CharSequence data, final Checksum algorithm )
092    {
093        return create( data, UTF8, algorithm );
094    }   //  create()
095
096    /**
097     *  Creates the hash for the given String, using the given algorithm.
098     *
099     *  @param  data    The input data.
100     *  @param  encoding    The encoding for the String.
101     *  @param  algorithm   The algorithm
102     *  @return A new instance of {@code Hash}.
103     */
104    public static Hash create( final CharSequence data, final Charset encoding, final Checksum algorithm )
105    {
106        return HashImpl.create( requireNonNullArgument( data, "data" ).toString().getBytes( requireNonNullArgument( encoding, "encoding" ) ), algorithm );
107    }   //  create()
108
109    /**
110     *  Creates the hash for the given file, using the given algorithm.
111     *
112     *  @param  data    The input data.
113     *  @param  algorithm   The algorithm
114     *  @return A new instance of {@code Hash}.
115     *  @throws IOException Problems to process the file.
116     */
117    public static Hash create( final File data, final Checksum algorithm ) throws IOException
118    {
119        return create( requireNonNullArgument( data, "data" ).toPath(), algorithm );
120    }   //  create()
121
122    /**
123     *  Creates the hash for the given file, using the given algorithm.
124     *
125     *  @param  data    The input data.
126     *  @param  algorithm   The algorithm
127     *  @return A new instance of {@code Hash}.
128     *  @throws IOException Problems to process the file.
129     */
130    public static Hash create( final Path data, final Checksum algorithm ) throws IOException
131    {
132        return HashImpl.create( data, algorithm );
133    }   //  create()
134
135    /**
136     *  Creates the hash for the given byte array, using the given algorithm.
137     *
138     *  @param  data    The input data.
139     *  @param  algorithm   The algorithm
140     *  @return A new instance of {@code Hash}.
141     */
142    public static Hash create( final byte [] data, final MessageDigest algorithm )
143    {
144        return HashImpl.create( data, algorithm );
145    }   //  create()
146
147    /**
148     *  Creates the hash for the given String, using the given algorithm.
149     *
150     *  @param  data    The input data.
151     *  @param  algorithm   The algorithm
152     *  @return A new instance of {@code Hash}.
153     */
154    public static Hash create( final CharSequence data, final MessageDigest algorithm )
155    {
156        return create( data, UTF8, algorithm );
157    }   //  create()
158
159    /**
160     *  Creates the hash for the given String, using the given algorithm.
161     *
162     *  @param  data    The input data.
163     *  @param  encoding    The encoding for the String.
164     *  @param  algorithm   The algorithm
165     *  @return A new instance of {@code Hash}.
166     */
167    public static Hash create( final CharSequence data, final Charset encoding, final MessageDigest algorithm )
168    {
169        return HashImpl.create( requireNonNullArgument( data, "data" ).toString().getBytes( requireNonNullArgument( encoding, "encoding" ) ), algorithm );
170    }   //  create()
171
172    /**
173     *  Creates the hash for the given file, using the given algorithm.
174     *
175     *  @param  data    The input data.
176     *  @param  algorithm   The algorithm
177     *  @throws IOException Problems to process the file.
178     *  @return A new instance of {@code Hash}.
179     */
180    public static Hash create( final File data, final MessageDigest algorithm ) throws IOException
181    {
182        return create( requireNonNullArgument( data, "data" ).toPath(), algorithm );
183    }   //  create()
184
185    /**
186     *  Creates the hash for the given file, using the given algorithm.
187     *
188     *  @param  data    The input data.
189     *  @param  algorithm   The algorithm
190     *  @return A new instance of {@code Hash}.
191     *  @throws IOException Problems to process the file.
192     */
193    public static Hash create( final Path data, final MessageDigest algorithm ) throws IOException
194    {
195        return HashImpl.create( data, algorithm );
196    }   //  create()
197
198    /**
199     *  Creates an instance of {@code Hash} from the given byte array.
200     *
201     *  @param  hashValue   The hash value.
202     *  @return A new instance of {@code Hash}.
203     */
204    public static Hash from( final byte [] hashValue ) { return new HashImpl( hashValue ); }
205
206    /**
207     *  Creates an instance of {@code Hash} from the given String.
208     *
209     *  @param  hashValue   The hash value.
210     *  @return A new instance of {@code Hash}.
211     */
212    public static Hash from( final CharSequence hashValue ) { return HashImpl.from( hashValue ); }
213
214    /**
215     *  Returns this hash as a number.
216     *
217     *  @return The number.
218     */
219    public default BigInteger number() { return new BigInteger( bytes() ); }
220
221    /**
222     *  Validates whether the given hash value matches with this hash instance.
223     *
224     *  @param  hashValue   The hash value to test.
225     *  @return {@code true} if the hash value matches with this hash instance,
226     *      {@code false} otherwise.
227     */
228    public default boolean validate( final byte [] hashValue ) { return Arrays.equals( bytes(), hashValue ); }
229
230    /**
231     *  Validates whether the given hash value matches with this hash instance.
232     *
233     *  @param  hashValue   The hash value to test.
234     *  @return {@code true} if the hash value matches with this hash instance,
235     *      {@code false} otherwise.
236     */
237    public default boolean validate( final long hashValue ) { return number().longValue() == hashValue; }
238
239    /**
240     *  Validates whether the given hash value matches with this hash instance.
241     *
242     *  @param  hashValue   The hash value to test.
243     *  @return {@code true} if the hash value matches with this hash instance,
244     *      {@code false} otherwise.
245     */
246    public default boolean validate( final CharSequence hashValue )
247    {
248        return toString().toLowerCase( ROOT )
249            .equals( requireNonNullArgument( hashValue, "hashValue" ).toString().toLowerCase( ROOT ) );
250    }   //  validate()
251}
252//  interface Hash
253
254/*
255 *  End of File
256 */