diff --git a/parquet-cli/src/main/java/org/apache/parquet/cli/BaseCommand.java b/parquet-cli/src/main/java/org/apache/parquet/cli/BaseCommand.java index 0c8841b05c..9e12102e02 100644 --- a/parquet-cli/src/main/java/org/apache/parquet/cli/BaseCommand.java +++ b/parquet-cli/src/main/java/org/apache/parquet/cli/BaseCommand.java @@ -20,6 +20,7 @@ package org.apache.parquet.cli; import com.beust.jcommander.internal.Lists; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import com.google.common.io.CharStreams; import com.google.common.io.Resources; @@ -428,16 +429,22 @@ private void parseAndSetColumnKeys(String columnKeysStr, ConfigurableKeyRetrieve } } - private byte[] hexToBytes(String hex) { - + @VisibleForTesting + byte[] hexToBytes(String hex) { + String originalHex = hex; if (hex.startsWith("0x") || hex.startsWith("0X")) { hex = hex.substring(2); } int len = hex.length(); + Preconditions.checkArgument(len % 2 == 0, "Invalid hex string: %s", originalHex); + byte[] data = new byte[len / 2]; for (int i = 0; i < len; i += 2) { - data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4) + Character.digit(hex.charAt(i + 1), 16)); + int high = Character.digit(hex.charAt(i), 16); + int low = Character.digit(hex.charAt(i + 1), 16); + Preconditions.checkArgument(high >= 0 && low >= 0, "Invalid hex string: %s", originalHex); + data[i / 2] = (byte) ((high << 4) + low); } return data; } diff --git a/parquet-cli/src/test/java/org/apache/parquet/cli/BaseCommandTest.java b/parquet-cli/src/test/java/org/apache/parquet/cli/BaseCommandTest.java index 1f441c3348..731f799e1c 100644 --- a/parquet-cli/src/test/java/org/apache/parquet/cli/BaseCommandTest.java +++ b/parquet-cli/src/test/java/org/apache/parquet/cli/BaseCommandTest.java @@ -18,6 +18,9 @@ */ package org.apache.parquet.cli; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + import java.io.IOException; import java.net.URI; import java.util.List; @@ -62,6 +65,29 @@ public void qualifiedURIResourceURITest() throws IOException { Assert.assertEquals("/a", uri.getPath()); } + @Test + public void hexToBytes() { + assertThat(this.command.hexToBytes("0x10")).containsExactly(0x10); + assertThat(this.command.hexToBytes("0x0506")).containsExactly(0x05, 0x06); + assertThat(this.command.hexToBytes("0506")).containsExactly(0x05, 0x06); + assertThat(this.command.hexToBytes("0x010203")).containsExactly(0x01, 0x02, 0x03); + } + + @Test + public void hexToBytesRejectsInvalidHexString() { + assertThatThrownBy(() -> this.command.hexToBytes("0x011")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Invalid hex string: 0x011"); + + assertThatThrownBy(() -> this.command.hexToBytes("0xABZZ")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Invalid hex string: 0xABZZ"); + + assertThatThrownBy(() -> this.command.hexToBytes("0xabgg")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Invalid hex string: 0xabgg"); + } + // For Windows @Test public void qualifiedPathTestForWindows() throws IOException {