From 849753befe806bb6f5cb60bb4c58a4c44ecb1ff1 Mon Sep 17 00:00:00 2001 From: Markus Rathgeb Date: Mon, 10 Jun 2019 17:07:04 +0200 Subject: [PATCH] small improvements of hexutils API and impl. (#862) Signed-off-by: Markus Rathgeb --- .../eclipse/smarthome/core/util/HexUtils.java | 82 ++++++++++++------- .../smarthome/core/util/HexUtilsTest.java | 0 2 files changed, 51 insertions(+), 31 deletions(-) rename {itests/org.openhab.core.tests/src/main => bundles/org.openhab.core/src/test}/java/org/eclipse/smarthome/core/util/HexUtilsTest.java (100%) diff --git a/bundles/org.openhab.core/src/main/java/org/eclipse/smarthome/core/util/HexUtils.java b/bundles/org.openhab.core/src/main/java/org/eclipse/smarthome/core/util/HexUtils.java index b21baa428..f598d3cf8 100644 --- a/bundles/org.openhab.core/src/main/java/org/eclipse/smarthome/core/util/HexUtils.java +++ b/bundles/org.openhab.core/src/main/java/org/eclipse/smarthome/core/util/HexUtils.java @@ -12,8 +12,7 @@ */ package org.eclipse.smarthome.core.util; -import java.util.Arrays; -import java.util.stream.Collectors; +import java.nio.charset.StandardCharsets; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; @@ -28,7 +27,8 @@ import org.eclipse.jdt.annotation.Nullable; public class HexUtils { // used for hex conversions - private static final char[] hexArray = "0123456789ABCDEF".toCharArray(); + private static final byte[] HEX = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', + 'F' }; private static final int ASCII_DIGITS_START_POSITION = 48; private static final int ASCII_UPPERCASE_LETTERS_START_POSITION = 65; @@ -46,10 +46,25 @@ public class HexUtils { * @return the corresponding hex string */ public static String bytesToHex(byte[] bytes, @Nullable CharSequence delimiter) { - return Arrays.stream(toObjects(bytes)).map(b -> { - int v = b & 0xFF; - return "" + hexArray[v >>> 4] + hexArray[v & 0x0F]; - }).collect(Collectors.joining(delimiter != null ? delimiter : "")); + return bytesToHexInt(bytes, delimiter != null ? delimiter : ""); + } + + private static String bytesToHexInt(byte[] bytes, CharSequence delimiter) { + if (bytes.length == 0) { + return ""; + } + final StringBuilder sb = new StringBuilder(bytes.length * 2 + delimiter.length() * (bytes.length - 1)); + int pos = 0; + while (pos < bytes.length - 1) { + final byte[] hex = byteToHex(bytes[pos++]); + sb.append((char) hex[0]); + sb.append((char) hex[1]); + sb.append(delimiter); + } + final byte[] hex = byteToHex(bytes[pos++]); + sb.append((char) hex[0]); + sb.append((char) hex[1]); + return sb.toString(); } /** @@ -59,13 +74,14 @@ public class HexUtils { * @return the corresponding hex string */ public static String bytesToHex(byte[] bytes) { - return bytesToHex(bytes, null); + return bytesToHexInt(bytes, ""); } - private static Byte[] toObjects(byte[] bytes) { - Byte[] bytesObjects = new Byte[bytes.length]; - Arrays.setAll(bytesObjects, n -> bytes[n]); - return bytesObjects; + public static byte[] byteToHex(final byte value) { + final byte[] out = new byte[2]; + out[0] = HEX[(value >>> 4) & 0x0F]; + out[1] = HEX[value & 0x0F]; + return out; } /** @@ -79,17 +95,16 @@ public class HexUtils { // first convert to upper case to ease the rest String ucHexString = hexString.toUpperCase(); - Byte[] bytesObjects = Arrays.stream(ucHexString.split(delimiter)).map(s -> { - if (s.length() != 2) { + final String[] splitted = ucHexString.split(delimiter); + + final byte[] bytes = new byte[splitted.length]; + int pos = 0; + for (final String part : splitted) { + final byte[] in = part.getBytes(StandardCharsets.UTF_8); + if (in.length != 2) { throw new IllegalArgumentException("hexString needs to have an even length: " + hexString); } - - return (byte) (hexCharacterToBin(s.charAt(0)) * 16 + hexCharacterToBin(s.charAt(1))); - }).toArray(Byte[]::new); - - byte[] bytes = new byte[bytesObjects.length]; - for (int i = 0; i < bytesObjects.length; i++) { - bytes[i] = bytesObjects[i]; + bytes[pos++] = (byte) (unhex(in[0]) << 4 | unhex(in[1])); } return bytes; } @@ -104,20 +119,25 @@ public class HexUtils { return hexToBytes(hexString, "(?<=\\G.{2})"); } + public static byte hexToByte(byte high, byte low) { + return (byte) ((unhex(high) << 4) | unhex(low)); + } + /** - * Convert an upper case hex character to a byte + * Convert an hex byte created by this utilities back. * - * @param chacacter an upper case hex character - * @return the byte value of the character - * @throws IllegalArgumentException if a value is found which is not an upper case hex character + * @param value the byte created by the hex array + * @return the byte value + * @throws IllegalArgumentException if a value is invalid */ - private static byte hexCharacterToBin(char character) { - if ('0' <= character && character <= '9') { - return (byte) (character - ASCII_DIGITS_START_POSITION); - } else if ('A' <= character && character <= 'F') { - return (byte) (character - ASCII_UPPERCASE_LETTERS_START_POSITION + 10); + private static byte unhex(byte value) { + if ('0' <= value && value <= '9') { + return (byte) (value - ASCII_DIGITS_START_POSITION); + } else if ('A' <= value && value <= 'F') { + return (byte) (value - ASCII_UPPERCASE_LETTERS_START_POSITION + 10); } else { - throw new IllegalArgumentException("hexString contains illegal character for hexToBytes: " + character); + throw new IllegalArgumentException("hexString contains illegal character for hexToBytes: " + value); } } + } diff --git a/itests/org.openhab.core.tests/src/main/java/org/eclipse/smarthome/core/util/HexUtilsTest.java b/bundles/org.openhab.core/src/test/java/org/eclipse/smarthome/core/util/HexUtilsTest.java similarity index 100% rename from itests/org.openhab.core.tests/src/main/java/org/eclipse/smarthome/core/util/HexUtilsTest.java rename to bundles/org.openhab.core/src/test/java/org/eclipse/smarthome/core/util/HexUtilsTest.java