diff --git a/src/main/java/org/apache/commons/codec/cli/Digest.java b/src/main/java/org/apache/commons/codec/cli/Digest.java index c887e495da..7e1f528363 100644 --- a/src/main/java/org/apache/commons/codec/cli/Digest.java +++ b/src/main/java/org/apache/commons/codec/cli/Digest.java @@ -14,8 +14,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.apache.commons.codec.cli; +import java.io.BufferedInputStream; import java.io.File; import java.io.IOException; import java.nio.charset.Charset; @@ -36,18 +38,17 @@ */ public class Digest { + private static final String EMPTY = ""; + /** - * 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. + * 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. * *
* The algorithm can also be {@code ALL} or {@code *} to output one line for each known algorithm. *
* - * @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. + * @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 { @@ -62,16 +63,11 @@ 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())); + 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); - } + this.inputs = argsLength > 1 ? Arrays.copyOfRange(args, 1, argsLength) : null; } private void println(final String prefix, final byte[] digest) { @@ -84,25 +80,26 @@ private void println(final String prefix, final byte[] digest, final String file // 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 : "")); + System.out.println(prefix + Hex.encodeHexString(digest) + (fileName != null ? " " + fileName : EMPTY)); } private void run() throws IOException { + final BufferedInputStream systemIn = inputs != null ? null : new BufferedInputStream(System.in); if (algorithm.equalsIgnoreCase("ALL") || algorithm.equals("*")) { - run(MessageDigestAlgorithms.values()); + run(systemIn, MessageDigestAlgorithms.values()); return; } final MessageDigest messageDigest = DigestUtils.getDigest(algorithm, null); if (messageDigest != null) { - run("", messageDigest); + run(systemIn, EMPTY, messageDigest); } else { - run("", DigestUtils.getDigest(algorithm.toUpperCase(Locale.ROOT))); + run(systemIn, EMPTY, DigestUtils.getDigest(algorithm.toUpperCase(Locale.ROOT))); } } - private void run(final String prefix, final MessageDigest messageDigest) throws IOException { + private void run(final BufferedInputStream systemIn, final String prefix, final MessageDigest messageDigest) throws IOException { if (inputs == null) { - println(prefix, DigestUtils.digest(messageDigest, System.in)); + println(prefix, DigestUtils.digest(messageDigest, systemIn)); return; } for (final String source : inputs) { @@ -122,22 +119,29 @@ private void run(final String prefix, final MessageDigest messageDigest) throws } } - 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 BufferedInputStream systemIn, final String prefix, final String messageDigestAlgorithm) throws IOException { + run(systemIn, prefix, DigestUtils.getDigest(messageDigestAlgorithm)); } - private void run(final String[] digestAlgorithms) throws IOException { + private void run(final BufferedInputStream systemIn, final String[] digestAlgorithms) throws IOException { for (final String messageDigestAlgorithm : digestAlgorithms) { if (DigestUtils.isAvailable(messageDigestAlgorithm)) { - run(messageDigestAlgorithm + " ", messageDigestAlgorithm); + if (systemIn != null) { + // 1 GB arbitrary default. + systemIn.mark(Integer.getInteger(getClass().getName() + ".markReadLimit", 1_073_741_824)); + } + run(systemIn, messageDigestAlgorithm + " ", messageDigestAlgorithm); + if (systemIn != null) { + systemIn.reset(); + } + } + } + } + + 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()); } } } diff --git a/src/test/java/org/apache/commons/codec/cli/DigestTest.java b/src/test/java/org/apache/commons/codec/cli/DigestTest.java index 1955c78e2d..84e701d507 100644 --- a/src/test/java/org/apache/commons/codec/cli/DigestTest.java +++ b/src/test/java/org/apache/commons/codec/cli/DigestTest.java @@ -18,7 +18,16 @@ package org.apache.commons.codec.cli; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.PrintStream; +import java.nio.charset.StandardCharsets; + +import org.apache.commons.lang3.JavaVersion; +import org.apache.commons.lang3.SystemUtils; import org.junit.jupiter.api.Test; /** @@ -26,6 +35,41 @@ */ class DigestTest { + @Test + void testAllAlgorithmsUseTheSameStandardInput() throws Exception { + final InputStream originalIn = System.in; + final PrintStream originalOut = System.out; + final ByteArrayOutputStream captured = new ByteArrayOutputStream(); + try { + System.setIn(new ByteArrayInputStream("abc".getBytes(StandardCharsets.UTF_8))); + System.setOut(new PrintStream(captured, true, StandardCharsets.UTF_8.name())); + Digest.main(new String[] { "ALL" }); + } finally { + System.setIn(originalIn); + System.setOut(originalOut); + } + final String output = captured.toString(StandardCharsets.UTF_8.name()); + assertTrue(output.contains("MD2 da853b0d3f88d99b30283a69e6ded6bb"), output); + assertTrue(output.contains("MD5 900150983cd24fb0d6963f7d28e17f72"), output); + assertTrue(output.contains("SHA-1 a9993e364706816aba3e25717850c26c9cd0d89d"), output); + assertTrue(output.contains("SHA-224 23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7"), output); + assertTrue(output.contains("SHA-256 ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"), output); + assertTrue(output.contains("SHA-384 cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7"), output); + assertTrue(output.contains( + "SHA-512 ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"), + output); + assertTrue(output.contains("SHA-512/224 4634270f707b6a54daae7530460842e20e37ed265ceee9a43e8924aa"), output); + assertTrue(output.contains("SHA-512/256 53048e2681941ef99b2e29b76b4c7dabe4c2d0c634fc6d46e0e2f13107e7af23"), output); + if (SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_9)) { + assertTrue(output.contains("SHA3-224 e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf"), output); + assertTrue(output.contains("SHA3-256 3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532"), output); + assertTrue(output.contains("SHA3-384 ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25"), output); + assertTrue(output.contains( + "SHA3-512 b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0"), + output); + } + } + /** * Tests if empty arguments are handled correctly. */