8263754: HexFormat 'fromHex' methods should be static

Reviewed-by: redestad, naoto, chegar
This commit is contained in:
Roger Riggs 2021-03-29 20:38:10 +00:00
parent a5d7de2351
commit 8cf1c62c34
5 changed files with 39 additions and 54 deletions

View File

@ -877,7 +877,7 @@ public final class HexFormat {
* @return {@code true} if the character is valid a hexadecimal character, * @return {@code true} if the character is valid a hexadecimal character,
* otherwise {@code false} * otherwise {@code false}
*/ */
public boolean isHexDigit(int ch) { public static boolean isHexDigit(int ch) {
return ((ch >>> 8) == 0 && DIGITS[ch] >= 0); return ((ch >>> 8) == 0 && DIGITS[ch] >= 0);
} }
@ -889,13 +889,12 @@ public final class HexFormat {
* <li>{@code (ch - 'A' + 10)} for {@code 'A'} through {@code 'F'} inclusive, and * <li>{@code (ch - 'A' + 10)} for {@code 'A'} through {@code 'F'} inclusive, and
* <li>{@code (ch - 'a' + 10)} for {@code 'a'} through {@code 'f'} inclusive. * <li>{@code (ch - 'a' + 10)} for {@code 'a'} through {@code 'f'} inclusive.
* </ul> * </ul>
* The delimiter, prefix, suffix, and uppercase parameters are not used.
* *
* @param ch a character or codepoint * @param ch a character or codepoint
* @return the value {@code 0-15} * @return the value {@code 0-15}
* @throws NumberFormatException if the codepoint is not a hexadecimal character * @throws NumberFormatException if the codepoint is not a hexadecimal character
*/ */
public int fromHexDigit(int ch) { public static int fromHexDigit(int ch) {
int value; int value;
if ((ch >>> 8) == 0 && (value = DIGITS[ch]) >= 0) { if ((ch >>> 8) == 0 && (value = DIGITS[ch]) >= 0) {
return value; return value;
@ -907,7 +906,6 @@ public final class HexFormat {
* Returns a value parsed from two hexadecimal characters in a string. * Returns a value parsed from two hexadecimal characters in a string.
* The characters in the range from {@code index} to {@code index + 1}, * The characters in the range from {@code index} to {@code index + 1},
* inclusive, must be valid hex digits according to {@link #fromHexDigit(int)}. * inclusive, must be valid hex digits according to {@link #fromHexDigit(int)}.
* The delimiter, prefix, suffix, and uppercase parameters are not used.
* *
* @param string a CharSequence containing the characters * @param string a CharSequence containing the characters
* @param index the index of the first character of the range * @param index the index of the first character of the range
@ -917,7 +915,7 @@ public final class HexFormat {
* @throws IndexOutOfBoundsException if the range is out of bounds * @throws IndexOutOfBoundsException if the range is out of bounds
* for the {@code CharSequence} * for the {@code CharSequence}
*/ */
private int fromHexDigits(CharSequence string, int index) { private static int fromHexDigits(CharSequence string, int index) {
Objects.requireNonNull(string, "string"); Objects.requireNonNull(string, "string");
int high = fromHexDigit(string.charAt(index)); int high = fromHexDigit(string.charAt(index));
int low = fromHexDigit(string.charAt(index + 1)); int low = fromHexDigit(string.charAt(index + 1));
@ -929,7 +927,6 @@ public final class HexFormat {
* The hexadecimal characters are parsed from most significant to least significant * The hexadecimal characters are parsed from most significant to least significant
* using {@link #fromHexDigit(int)} to form an unsigned value. * using {@link #fromHexDigit(int)} to form an unsigned value.
* The value is zero extended to 32 bits and is returned as an {@code int}. * The value is zero extended to 32 bits and is returned as an {@code int}.
* The delimiter, prefix, suffix, and uppercase parameters are not used.
* *
* @apiNote * @apiNote
* {@link Integer#parseInt(String, int) Integer.parseInt(s, 16)} and * {@link Integer#parseInt(String, int) Integer.parseInt(s, 16)} and
@ -944,7 +941,7 @@ public final class HexFormat {
* @throws IllegalArgumentException if the string length is greater than eight (8) or * @throws IllegalArgumentException if the string length is greater than eight (8) or
* if any of the characters is not a hexadecimal character * if any of the characters is not a hexadecimal character
*/ */
public int fromHexDigits(CharSequence string) { public static int fromHexDigits(CharSequence string) {
Objects.requireNonNull(string, "string"); Objects.requireNonNull(string, "string");
int length = checkDigitCount(0, string.length(), 8); int length = checkDigitCount(0, string.length(), 8);
int value = 0; int value = 0;
@ -961,7 +958,6 @@ public final class HexFormat {
* are parsed from most significant to least significant * are parsed from most significant to least significant
* using {@link #fromHexDigit(int)} to form an unsigned value. * using {@link #fromHexDigit(int)} to form an unsigned value.
* The value is zero extended to 32 bits and is returned as an {@code int}. * The value is zero extended to 32 bits and is returned as an {@code int}.
* The delimiter, prefix, suffix, and uppercase parameters are not used.
* *
* @apiNote * @apiNote
* {@link Integer#parseInt(String, int) Integer.parseInt(s, 16)} and * {@link Integer#parseInt(String, int) Integer.parseInt(s, 16)} and
@ -980,7 +976,7 @@ public final class HexFormat {
* @throws IllegalArgumentException if length of the range is greater than eight (8) or * @throws IllegalArgumentException if length of the range is greater than eight (8) or
* if any of the characters is not a hexadecimal character * if any of the characters is not a hexadecimal character
*/ */
public int fromHexDigits(CharSequence string, int fromIndex, int toIndex) { public static int fromHexDigits(CharSequence string, int fromIndex, int toIndex) {
Objects.requireNonNull(string, "string"); Objects.requireNonNull(string, "string");
Objects.checkFromToIndex(fromIndex, toIndex, string.length()); Objects.checkFromToIndex(fromIndex, toIndex, string.length());
int length = checkDigitCount(fromIndex, toIndex, 8); int length = checkDigitCount(fromIndex, toIndex, 8);
@ -996,7 +992,6 @@ public final class HexFormat {
* The hexadecimal characters are parsed from most significant to least significant * The hexadecimal characters are parsed from most significant to least significant
* using {@link #fromHexDigit(int)} to form an unsigned value. * using {@link #fromHexDigit(int)} to form an unsigned value.
* The value is zero extended to 64 bits and is returned as a {@code long}. * The value is zero extended to 64 bits and is returned as a {@code long}.
* The delimiter, prefix, suffix, and uppercase parameters are not used.
* *
* @apiNote * @apiNote
* {@link Long#parseLong(String, int) Long.parseLong(s, 16)} and * {@link Long#parseLong(String, int) Long.parseLong(s, 16)} and
@ -1011,7 +1006,7 @@ public final class HexFormat {
* @throws IllegalArgumentException if the string length is greater than sixteen (16) or * @throws IllegalArgumentException if the string length is greater than sixteen (16) or
* if any of the characters is not a hexadecimal character * if any of the characters is not a hexadecimal character
*/ */
public long fromHexDigitsToLong(CharSequence string) { public static long fromHexDigitsToLong(CharSequence string) {
Objects.requireNonNull(string, "string"); Objects.requireNonNull(string, "string");
int length = checkDigitCount(0, string.length(), 16); int length = checkDigitCount(0, string.length(), 16);
long value = 0L; long value = 0L;
@ -1028,7 +1023,6 @@ public final class HexFormat {
* are parsed from most significant to least significant * are parsed from most significant to least significant
* using {@link #fromHexDigit(int)} to form an unsigned value. * using {@link #fromHexDigit(int)} to form an unsigned value.
* The value is zero extended to 64 bits and is returned as a {@code long}. * The value is zero extended to 64 bits and is returned as a {@code long}.
* The delimiter, prefix, suffix, and uppercase parameters are not used.
* *
* @apiNote * @apiNote
* {@link Long#parseLong(String, int) Long.parseLong(s, 16)} and * {@link Long#parseLong(String, int) Long.parseLong(s, 16)} and
@ -1047,7 +1041,7 @@ public final class HexFormat {
* @throws IllegalArgumentException if the length of the range is greater than sixteen (16) or * @throws IllegalArgumentException if the length of the range is greater than sixteen (16) or
* if any of the characters is not a hexadecimal character * if any of the characters is not a hexadecimal character
*/ */
public long fromHexDigitsToLong(CharSequence string, int fromIndex, int toIndex) { public static long fromHexDigitsToLong(CharSequence string, int fromIndex, int toIndex) {
Objects.requireNonNull(string, "string"); Objects.requireNonNull(string, "string");
Objects.checkFromToIndex(fromIndex, toIndex, string.length()); Objects.checkFromToIndex(fromIndex, toIndex, string.length());
int length = checkDigitCount(fromIndex, toIndex, 16); int length = checkDigitCount(fromIndex, toIndex, 16);

View File

@ -815,11 +815,10 @@ class RevocationChecker extends PKIXRevocationChecker {
* Removes any non-hexadecimal characters from a string. * Removes any non-hexadecimal characters from a string.
*/ */
private static String stripOutSeparators(String value) { private static String stripOutSeparators(String value) {
HexFormat hex = HexFormat.of();
char[] chars = value.toCharArray(); char[] chars = value.toCharArray();
StringBuilder hexNumber = new StringBuilder(); StringBuilder hexNumber = new StringBuilder();
for (int i = 0; i < chars.length; i++) { for (int i = 0; i < chars.length; i++) {
if (hex.isHexDigit(chars[i])) { if (HexFormat.isHexDigit(chars[i])) {
hexNumber.append(chars[i]); hexNumber.append(chars[i]);
} }
} }

View File

@ -40,7 +40,6 @@ import java.security.cert.URICertStoreParameters;
import java.security.interfaces.ECKey; import java.security.interfaces.ECKey;
import java.security.interfaces.EdECKey; import java.security.interfaces.EdECKey;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.ECParameterSpec; import java.security.spec.ECParameterSpec;
import java.text.Collator; import java.text.Collator;
import java.text.MessageFormat; import java.text.MessageFormat;
@ -4574,16 +4573,15 @@ public final class Main {
break; break;
case -1: case -1:
ObjectIdentifier oid = ObjectIdentifier.of(name); ObjectIdentifier oid = ObjectIdentifier.of(name);
HexFormat hexFmt = HexFormat.of();
byte[] data = null; byte[] data = null;
if (value != null) { if (value != null) {
data = new byte[value.length() / 2 + 1]; data = new byte[value.length() / 2 + 1];
int pos = 0; int pos = 0;
for (char c: value.toCharArray()) { for (char c: value.toCharArray()) {
if (!hexFmt.isHexDigit(c)) { if (!HexFormat.isHexDigit(c)) {
continue; continue;
} }
int hex = hexFmt.fromHexDigit(c); int hex = HexFormat.fromHexDigit(c);
if (pos % 2 == 0) { if (pos % 2 == 0) {
data[pos/2] = (byte)(hex << 4); data[pos/2] = (byte)(hex << 4);
} else { } else {

View File

@ -29,7 +29,6 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.Reader; import java.io.Reader;
import java.security.AccessController;
import java.text.Normalizer; import java.text.Normalizer;
import java.util.*; import java.util.*;
@ -251,7 +250,6 @@ public class AVA implements DerEncoder {
private static DerValue parseHexString private static DerValue parseHexString
(Reader in, int format) throws IOException { (Reader in, int format) throws IOException {
HexFormat hex = HexFormat.of();
int c; int c;
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte b = 0; byte b = 0;
@ -263,7 +261,7 @@ public class AVA implements DerEncoder {
break; break;
} }
try { try {
int cVal = hex.fromHexDigit(c); // throws on invalid character int cVal = HexFormat.fromHexDigit(c); // throws on invalid character
if ((cNdx % 2) == 1) { if ((cNdx % 2) == 1) {
b = (byte)((b * 16) + (byte)(cVal)); b = (byte)((b * 16) + (byte)(cVal));
baos.write(b); baos.write(b);
@ -502,14 +500,13 @@ public class AVA implements DerEncoder {
private static Byte getEmbeddedHexPair(int c1, Reader in) private static Byte getEmbeddedHexPair(int c1, Reader in)
throws IOException { throws IOException {
HexFormat hex = HexFormat.of(); if (HexFormat.isHexDigit(c1)) {
if (hex.isHexDigit(c1)) {
int c2 = readChar(in, "unexpected EOF - " + int c2 = readChar(in, "unexpected EOF - " +
"escaped hex value must include two valid digits"); "escaped hex value must include two valid digits");
if (hex.isHexDigit(c2)) { if (HexFormat.isHexDigit(c2)) {
int hi = hex.fromHexDigit(c1); int hi = HexFormat.fromHexDigit(c1);
int lo = hex.fromHexDigit(c2); int lo = HexFormat.fromHexDigit(c2);
return (byte)((hi<<4) + lo); return (byte)((hi<<4) + lo);
} else { } else {
throw new IOException throw new IOException

View File

@ -153,7 +153,7 @@ public class HexFormatTest {
HexFormat hex = HexFormat.of(); HexFormat hex = HexFormat.of();
for (int i = 0; i < 256; i++) { for (int i = 0; i < 256; i++) {
String actual = hex.toHexDigits((byte)i); String actual = hex.toHexDigits((byte)i);
int expected = hex.fromHexDigits(actual); int expected = HexFormat.fromHexDigits(actual);
assertEquals(expected, i, "fromHexDigits"); assertEquals(expected, i, "fromHexDigits");
assertEquals(actual.charAt(0), hex.toHighHexDigit((byte)i), assertEquals(actual.charAt(0), hex.toHighHexDigit((byte)i),
"first char mismatch"); "first char mismatch");
@ -164,9 +164,8 @@ public class HexFormatTest {
@Test @Test
static void testIsHexDigit() { static void testIsHexDigit() {
HexFormat hex = HexFormat.of();
for (int i = 0; i < 0x3ff; i++) { for (int i = 0; i < 0x3ff; i++) {
boolean actual = hex.isHexDigit(i); boolean actual = HexFormat.isHexDigit(i);
boolean expected = Character.digit(i, 16) >= 0; boolean expected = Character.digit(i, 16) >= 0;
assertEquals(actual, expected, "isHexDigit: " + i); assertEquals(actual, expected, "isHexDigit: " + i);
} }
@ -174,23 +173,21 @@ public class HexFormatTest {
@Test @Test
static void testFromHexDigit() { static void testFromHexDigit() {
HexFormat hex = HexFormat.of();
String chars = "0123456789ABCDEF0123456789abcdef"; String chars = "0123456789ABCDEF0123456789abcdef";
for (int i = 0; i < chars.length(); i++) { for (int i = 0; i < chars.length(); i++) {
int v = hex.fromHexDigit(chars.charAt(i)); int v = HexFormat.fromHexDigit(chars.charAt(i));
assertEquals(v, i & 0xf, "fromHex decode"); assertEquals(v, i & 0xf, "fromHex decode");
} }
} }
@Test @Test
static void testFromHexInvalid() { static void testFromHexInvalid() {
HexFormat hex = HexFormat.of();
for (int i = 0; i < 65536; i++) { for (int i = 0; i < 65536; i++) {
char ch = (char)i; char ch = (char)i;
if (ch > 0xff || Character.digit(ch, 16) < 0) { if (ch > 0xff || Character.digit(ch, 16) < 0) {
assertFalse(hex.isHexDigit(ch), "isHexDigit incorrect for '" + ch + "' = " + i); assertFalse(HexFormat.isHexDigit(ch), "isHexDigit incorrect for '" + ch + "' = " + i);
expectThrows(NumberFormatException.class, expectThrows(NumberFormatException.class,
() -> hex.fromHexDigit(ch)); () -> HexFormat.fromHexDigit(ch));
} }
} }
@ -208,7 +205,7 @@ public class HexFormatTest {
assertEquals(sb.charAt(0), hex.toHighHexDigit((byte)i), "MSB converted wrong"); assertEquals(sb.charAt(0), hex.toHighHexDigit((byte)i), "MSB converted wrong");
assertEquals(sb.charAt(1), hex.toLowHexDigit((byte)i), "LSB converted wrong"); assertEquals(sb.charAt(1), hex.toLowHexDigit((byte)i), "LSB converted wrong");
assertEquals(hex.fromHexDigits(sb), i, "hex.format(sb, byte) wrong"); assertEquals(HexFormat.fromHexDigits(sb), i, "hex.format(sb, byte) wrong");
} }
} }
@ -244,7 +241,7 @@ public class HexFormatTest {
for (int i = 0; i < chars.length(); i += 2) { for (int i = 0; i < chars.length(); i += 2) {
final int ndx = i; final int ndx = i;
Throwable ex = expectThrows(NumberFormatException.class, Throwable ex = expectThrows(NumberFormatException.class,
() -> hex.fromHexDigits(chars.subSequence(ndx, ndx+2))); () -> HexFormat.fromHexDigits(chars.subSequence(ndx, ndx+2)));
System.out.println(ex); System.out.println(ex);
} }
} }
@ -289,10 +286,10 @@ public class HexFormatTest {
@Test @Test
static void testFromHexNPE() { static void testFromHexNPE() {
assertThrows(NPE, () -> HexFormat.of().fromHexDigits(null)); assertThrows(NPE, () -> HexFormat.fromHexDigits(null));
assertThrows(NPE, () -> HexFormat.of().fromHexDigits(null, 0, 0)); assertThrows(NPE, () -> HexFormat.fromHexDigits(null, 0, 0));
assertThrows(NPE, () -> HexFormat.of().fromHexDigitsToLong(null)); assertThrows(NPE, () -> HexFormat.fromHexDigitsToLong(null));
assertThrows(NPE, () -> HexFormat.of().fromHexDigitsToLong(null, 0, 0)); assertThrows(NPE, () -> HexFormat.fromHexDigitsToLong(null, 0, 0));
} }
@Test @Test
@ -314,9 +311,9 @@ public class HexFormatTest {
static void badFromHexDigits(String string, int fromIndex, int toIndex, static void badFromHexDigits(String string, int fromIndex, int toIndex,
Class<? extends Throwable> exClass) { Class<? extends Throwable> exClass) {
assertThrows(exClass, assertThrows(exClass,
() -> HexFormat.of().fromHexDigits(string, fromIndex, toIndex)); () -> HexFormat.fromHexDigits(string, fromIndex, toIndex));
assertThrows(exClass, assertThrows(exClass,
() -> HexFormat.of().fromHexDigitsToLong(string, fromIndex, toIndex)); () -> HexFormat.fromHexDigitsToLong(string, fromIndex, toIndex));
} }
// Verify IAE for strings that are too long for the target primitive type // Verify IAE for strings that are too long for the target primitive type
@ -324,13 +321,13 @@ public class HexFormatTest {
@Test @Test
static void wrongNumberDigits() { static void wrongNumberDigits() {
assertThrows(IllegalArgumentException.class, assertThrows(IllegalArgumentException.class,
() -> HexFormat.of().fromHexDigits("9876543210")); () -> HexFormat.fromHexDigits("9876543210"));
assertThrows(IllegalArgumentException.class, assertThrows(IllegalArgumentException.class,
() -> HexFormat.of().fromHexDigits("9876543210", 0, 9)); () -> HexFormat.fromHexDigits("9876543210", 0, 9));
assertThrows(IllegalArgumentException.class, assertThrows(IllegalArgumentException.class,
() -> HexFormat.of().fromHexDigitsToLong("98765432109876543210")); () -> HexFormat.fromHexDigitsToLong("98765432109876543210"));
assertThrows(IllegalArgumentException.class, assertThrows(IllegalArgumentException.class,
() -> HexFormat.of().fromHexDigitsToLong("98765432109876543210", 0, 17)); () -> HexFormat.fromHexDigitsToLong("98765432109876543210", 0, 17));
} }
@Test(dataProvider="HexFormattersParsers") @Test(dataProvider="HexFormattersParsers")
@ -572,7 +569,7 @@ public class HexFormatTest {
final int orig = 0x76543210; final int orig = 0x76543210;
for (int digits = 0; digits <= 8; digits++) { for (int digits = 0; digits <= 8; digits++) {
String s = hex.toHexDigits(orig, digits); String s = hex.toHexDigits(orig, digits);
long actual = hex.fromHexDigits(s, 0, digits); long actual = HexFormat.fromHexDigits(s, 0, digits);
System.out.printf(" digits: %2d, formatted: \"%s\", parsed as: 0x%08x%n", System.out.printf(" digits: %2d, formatted: \"%s\", parsed as: 0x%08x%n",
digits, s, actual); digits, s, actual);
assertEquals(s, allHex.substring(8 - digits, 8)); assertEquals(s, allHex.substring(8 - digits, 8));
@ -589,7 +586,7 @@ public class HexFormatTest {
final long orig = 0xfedcba9876543210L; final long orig = 0xfedcba9876543210L;
for (int digits = 0; digits <= 16; digits++) { for (int digits = 0; digits <= 16; digits++) {
String s = hex.toHexDigits(orig, digits); String s = hex.toHexDigits(orig, digits);
long actual = hex.fromHexDigitsToLong(s, 0, digits); long actual = HexFormat.fromHexDigitsToLong(s, 0, digits);
System.out.printf(" digits: %2d, formatted: \"%s\", parsed as: 0x%016xL%n", System.out.printf(" digits: %2d, formatted: \"%s\", parsed as: 0x%016xL%n",
digits, s, actual); digits, s, actual);
assertEquals(s, allHex.substring(16 - digits, 16)); assertEquals(s, allHex.substring(16 - digits, 16));
@ -605,7 +602,7 @@ public class HexFormatTest {
String allHex = "fedcba9876543210"; String allHex = "fedcba9876543210";
final long expected = 0xfedcba9876543210L; final long expected = 0xfedcba9876543210L;
String s = hex.toHexDigits(expected); String s = hex.toHexDigits(expected);
long actual = hex.fromHexDigitsToLong(s); long actual = HexFormat.fromHexDigitsToLong(s);
System.out.printf(" formatted: \"%s\", parsed as: 0x%016xL%n", s, actual); System.out.printf(" formatted: \"%s\", parsed as: 0x%016xL%n", s, actual);
assertEquals(s, allHex); assertEquals(s, allHex);
assertEquals(actual, expected); assertEquals(actual, expected);
@ -667,7 +664,7 @@ public class HexFormatTest {
String byteStr = hex.toHexDigits(b); String byteStr = hex.toHexDigits(b);
System.out.println(" " + byteStr); System.out.println(" " + byteStr);
byte byteVal = (byte)hex.fromHexDigits(byteStr); byte byteVal = (byte) HexFormat.fromHexDigits(byteStr);
assert(byteStr.equals("7f")); assert(byteStr.equals("7f"));
assert(b == byteVal); assert(b == byteVal);
assertTrue(byteStr.equals("7f")); assertTrue(byteStr.equals("7f"));
@ -677,20 +674,20 @@ public class HexFormatTest {
char c = 'A'; char c = 'A';
String charStr = hex.toHexDigits(c); String charStr = hex.toHexDigits(c);
System.out.println(" " + charStr); System.out.println(" " + charStr);
int charVal = hex.fromHexDigits(charStr); int charVal = HexFormat.fromHexDigits(charStr);
assert(c == charVal); assert(c == charVal);
assertTrue(c == charVal); assertTrue(c == charVal);
int i = 12345; int i = 12345;
String intStr = hex.toHexDigits(i); String intStr = hex.toHexDigits(i);
System.out.println(" " + intStr); System.out.println(" " + intStr);
int intVal = hex.fromHexDigits(intStr); int intVal = HexFormat.fromHexDigits(intStr);
assert(i == intVal); assert(i == intVal);
assertTrue(i == intVal); assertTrue(i == intVal);
long l = Long.MAX_VALUE; long l = Long.MAX_VALUE;
String longStr = hex.toHexDigits(l, 16); String longStr = hex.toHexDigits(l, 16);
long longVal = hex.fromHexDigitsToLong(longStr, 0, 16); long longVal = HexFormat.fromHexDigitsToLong(longStr, 0, 16);
System.out.println(" " + longStr + ", " + longVal); System.out.println(" " + longStr + ", " + longVal);
assert(l == longVal); assert(l == longVal);
assertTrue(l == longVal); assertTrue(l == longVal);