diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Hex.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Hex.java index fec85ea67..1ab9da8c6 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Hex.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Hex.java @@ -21,47 +21,54 @@ import java.io.IOException; public final class Hex { - private static final char[] DIGITS_LOWER = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + private static final byte[] DIGITS_LOWER = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + + private static int toDigit(char ch) throws IOException { + if (ch >= '0' && ch <= '9') { + return ch - '0'; + } + if (ch >= 'a' && ch <= 'f') { + return ch - 'a' + 10; + } + if (ch >= 'A' && ch <= 'F') { + return ch - 'A' + 10; + } + + throw new IOException("Illegal hexadecimal character " + ch); + } public static byte[] decodeHex(String str) throws IOException { - char[] data = str.toCharArray(); - int len = data.length; - - if ((len & 0x1) != 0) + if ((str.length() & 0x1) != 0) throw new IOException("Odd number of characters."); - byte[] out = new byte[len >> 1]; + int len = str.length() >> 1; + byte[] out = new byte[len]; - int i = 0; - for (int j = 0; j < len; i++) { - int f = toDigit(data[j], j) << 4; - j++; - f |= toDigit(data[j], j); - j++; - out[i] = (byte) (f & 0xFF); + for (int i = 0; i < len; i++) { + int j = i << 1; + int f = (toDigit(str.charAt(j)) << 4) | toDigit(str.charAt(j + 1)); + + out[i] = (byte) f; } return out; } + @SuppressWarnings("deprecation") public static String encodeHex(byte[] data) { int l = data.length; - char[] out = new char[l << 1]; + byte[] out = new byte[l << 1]; - int i = 0; - for (int j = 0; i < l; i++) { - out[(j++)] = DIGITS_LOWER[((0xF0 & data[i]) >>> 4)]; - out[(j++)] = DIGITS_LOWER[(0xF & data[i])]; + for (int i = 0; i < l; i++) { + byte b = data[i]; + + int j = i << 1; + out[j] = DIGITS_LOWER[((0xF0 & b) >>> 4)]; + out[j + 1] = DIGITS_LOWER[(0xF & b)]; } - return new String(out); + return new String(out, 0, 0, out.length); } - private static int toDigit(char ch, int index) throws IOException { - int digit = Character.digit(ch, 16); - if (digit == -1) - throw new IOException("Illegal hexadecimal character " + ch + " at index " + index); - return digit; + private Hex() { } - - private Hex() {} } diff --git a/HMCLCore/src/test/java/org/jackhuang/hmcl/util/HexTest.java b/HMCLCore/src/test/java/org/jackhuang/hmcl/util/HexTest.java new file mode 100644 index 000000000..074260020 --- /dev/null +++ b/HMCLCore/src/test/java/org/jackhuang/hmcl/util/HexTest.java @@ -0,0 +1,51 @@ +/* + * Hello Minecraft! Launcher + * Copyright (C) 2023 huangyuhui and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.jackhuang.hmcl.util; + +import org.junit.jupiter.api.Test; + +import java.io.IOException; + +import static org.junit.jupiter.api.Assertions.*; + +public class HexTest { + + @Test + public void testDecodeHex() throws IOException { + assertArrayEquals(new byte[0], Hex.decodeHex("")); + assertArrayEquals(new byte[1], Hex.decodeHex("00")); + assertArrayEquals(new byte[4], Hex.decodeHex("00000000")); + + assertArrayEquals( + new byte[]{0x10, (byte) 0xa3, (byte) 0xd1, (byte) 0xff}, + Hex.decodeHex("10a3D1Ff") + ); + + assertThrows(IOException.class, () -> Hex.decodeHex("1")); + assertThrows(IOException.class, () -> Hex.decodeHex("1a1")); + assertThrows(IOException.class, () -> Hex.decodeHex("1g")); + } + + @Test + public void testEncodeHex() { + assertEquals("", Hex.encodeHex(new byte[0])); + assertEquals("00", Hex.encodeHex(new byte[1])); + assertEquals("00000000", Hex.encodeHex(new byte[4])); + assertEquals("10a3d1ff", Hex.encodeHex(new byte[]{0x10, (byte) 0xa3, (byte) 0xd1, (byte) 0xff})); + } +}