Digest.java
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.codec.cli;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.Locale;
import java.util.Objects;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.codec.digest.MessageDigestAlgorithms;
/**
* A minimal command line to run digest over files, directories or a string.
*
* @see #main(String[])
* @since 1.11
*/
public class Digest {
/**
* Runs the digest algorithm in {@code args[0]} on the file in {@code args[1]}. If there is no {@code args[1]}, use
* standard input.
*
* <p>
* The algorithm can also be {@code ALL} or {@code *} to output one line for each known algorithm.
* </p>
*
* @param args
* {@code args[0]} is one of {@link MessageDigestAlgorithms} name,
* {@link MessageDigest} name, {@code ALL}, or {@code *}.
* {@code args[1+]} is a FILE/DIRECTORY/String.
* @throws IOException if an error occurs
*/
public static void main(final String[] args) throws IOException {
new Digest(args).run();
}
private final String algorithm;
private final String[] args;
private final String[] inputs;
private Digest(final String[] args) {
Objects.requireNonNull(args);
final int argsLength = args.length;
if (argsLength == 0) {
throw new IllegalArgumentException(
String.format("Usage: java %s [algorithm] [FILE|DIRECTORY|string] ...", Digest.class.getName()));
}
this.args = args;
this.algorithm = args[0];
if (argsLength <= 1) {
this.inputs = null;
} else {
this.inputs = Arrays.copyOfRange(args, 1, argsLength);
}
}
private void println(final String prefix, final byte[] digest) {
println(prefix, digest, null);
}
private void println(final String prefix, final byte[] digest, final String fileName) {
// The standard appears to be to print
// hex, space, then either space or '*' followed by file name
// where '*' is used for binary files
// shasum(1) has a -b option which generates " *" separator
// we don't distinguish binary files at present
System.out.println(prefix + Hex.encodeHexString(digest) + (fileName != null ? " " + fileName : ""));
}
private void run() throws IOException {
if (algorithm.equalsIgnoreCase("ALL") || algorithm.equals("*")) {
run(MessageDigestAlgorithms.values());
return;
}
final MessageDigest messageDigest = DigestUtils.getDigest(algorithm, null);
if (messageDigest != null) {
run("", messageDigest);
} else {
run("", DigestUtils.getDigest(algorithm.toUpperCase(Locale.ROOT)));
}
}
private void run(final String prefix, final MessageDigest messageDigest) throws IOException {
if (inputs == null) {
println(prefix, DigestUtils.digest(messageDigest, System.in));
return;
}
for (final String source : inputs) {
final File file = new File(source);
if (file.isFile()) {
println(prefix, DigestUtils.digest(messageDigest, file), source);
} else if (file.isDirectory()) {
final File[] listFiles = file.listFiles();
if (listFiles != null) {
run(prefix, messageDigest, listFiles);
}
} else {
// use the default charset for the command-line parameter
final byte[] bytes = source.getBytes(Charset.defaultCharset());
println(prefix, DigestUtils.digest(messageDigest, bytes));
}
}
}
private void run(final String prefix, final MessageDigest messageDigest, final File[] files) throws IOException {
for (final File file : files) {
if (file.isFile()) {
println(prefix, DigestUtils.digest(messageDigest, file), file.getName());
}
}
}
private void run(final String prefix, final String messageDigestAlgorithm) throws IOException {
run(prefix, DigestUtils.getDigest(messageDigestAlgorithm));
}
private void run(final String[] digestAlgorithms) throws IOException {
for (final String messageDigestAlgorithm : digestAlgorithms) {
if (DigestUtils.isAvailable(messageDigestAlgorithm)) {
run(messageDigestAlgorithm + " ", messageDigestAlgorithm);
}
}
}
@Override
public String toString() {
return String.format("%s %s", super.toString(), Arrays.toString(args));
}
}