From 1e3464179987ba445ac550f3b2feb0171db9876f Mon Sep 17 00:00:00 2001 From: fmahfoodh Date: Thu, 5 Nov 2026 15:05:58 +0400 Subject: [PATCH 1/2] Speed up bytesToHexString with a lookup table --- .../modifiablevariable/util/DataConverter.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/rub/nds/modifiablevariable/util/DataConverter.java b/src/main/java/de/rub/nds/modifiablevariable/util/DataConverter.java index db56b052..dc66e485 100644 --- a/src/main/java/de/rub/nds/modifiablevariable/util/DataConverter.java +++ b/src/main/java/de/rub/nds/modifiablevariable/util/DataConverter.java @@ -29,6 +29,8 @@ */ public final class DataConverter { + private static final char[] HEX_DIGITS = "0123456789ABCDEF".toCharArray(); + /** Private constructor to prevent instantiation of this utility class. */ private DataConverter() { super(); @@ -313,7 +315,7 @@ public static String bytesToHexString( if (array == null) { throw new IllegalArgumentException("Input byte array must not be null"); } - StringBuilder result = new StringBuilder(); + StringBuilder result = new StringBuilder(array.length * (usePrettyPrinting ? 4 : 3) + 1); if (initialNewLine && usePrettyPrinting) { result.append("\n"); } @@ -328,8 +330,7 @@ public static String bytesToHexString( result.append(" "); } } - byte b = array[i]; - result.append(String.format("%02X", b)); + appendHex(result, array[i]); } return result.toString(); } @@ -422,13 +423,17 @@ public static String bytesToRawHexString(byte[] array) { if (array == null) { throw new IllegalArgumentException("Input byte array must not be null"); } - StringBuilder result = new StringBuilder(); + StringBuilder result = new StringBuilder(array.length * 2); for (byte b : array) { - result.append(String.format("%02X", b)); + appendHex(result, b); } return result.toString(); } + private static void appendHex(StringBuilder sb, byte b) { + sb.append(HEX_DIGITS[(b >> 4) & 0x0F]).append(HEX_DIGITS[b & 0x0F]); + } + /** * Concatenates multiple arrays of the same type into a single array. * From 0041fa8af50dbedc2d10b7305d2df3f798a797eb Mon Sep 17 00:00:00 2001 From: fmahfoodh Date: Sat, 7 Nov 2026 11:02:20 +0400 Subject: [PATCH 2/2] Strip whitespace in UnformattedByteArrayAdapter without a regex --- .../util/UnformattedByteArrayAdapter.java | 22 ++++++++++++-- .../util/UnformattedByteArrayAdapterTest.java | 30 +++++++++++++++++++ 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/rub/nds/modifiablevariable/util/UnformattedByteArrayAdapter.java b/src/main/java/de/rub/nds/modifiablevariable/util/UnformattedByteArrayAdapter.java index 5b44d11c..207c78e9 100644 --- a/src/main/java/de/rub/nds/modifiablevariable/util/UnformattedByteArrayAdapter.java +++ b/src/main/java/de/rub/nds/modifiablevariable/util/UnformattedByteArrayAdapter.java @@ -60,8 +60,7 @@ public UnformattedByteArrayAdapter() { */ @Override public byte[] unmarshal(String value) { - value = value.replaceAll("\\s", ""); - return DataConverter.hexStringToByteArray(value); + return DataConverter.hexStringToByteArray(removeWhitespace(value)); } /** @@ -77,4 +76,23 @@ public byte[] unmarshal(String value) { public String marshal(byte[] value) { return DataConverter.bytesToHexString(value, false, false); } + + /** Same as {@code value.replaceAll("\\s", "")}, without compiling a pattern per call. */ + private static String removeWhitespace(String value) { + StringBuilder builder = null; + for (int i = 0; i < value.length(); i++) { + char c = value.charAt(i); + boolean whitespace = + c == ' ' || c == '\t' || c == '\n' || c == '\u000B' || c == '\f' || c == '\r'; + if (whitespace) { + if (builder == null) { + builder = new StringBuilder(value.length()); + builder.append(value, 0, i); + } + } else if (builder != null) { + builder.append(c); + } + } + return builder == null ? value : builder.toString(); + } } diff --git a/src/test/java/de/rub/nds/modifiablevariable/util/UnformattedByteArrayAdapterTest.java b/src/test/java/de/rub/nds/modifiablevariable/util/UnformattedByteArrayAdapterTest.java index 27194b50..bd2c7410 100644 --- a/src/test/java/de/rub/nds/modifiablevariable/util/UnformattedByteArrayAdapterTest.java +++ b/src/test/java/de/rub/nds/modifiablevariable/util/UnformattedByteArrayAdapterTest.java @@ -77,4 +77,34 @@ void testUnmarshalOnlyWhitespace() throws Exception { assertArrayEquals(expected, adapter.unmarshal(input)); } + + @Test + void testUnmarshalStripsWhitespaceLikeRegex() { + java.util.Random random = new java.util.Random(7); + char[] alphabet = { + '0', 'a', 'F', ' ', '\t', '\n', '\u000B', '\f', '\r', '\u00A0', '\u2028' + }; + for (int n = 0; n < 2000; n++) { + StringBuilder raw = new StringBuilder(); + int length = random.nextInt(40); + for (int i = 0; i < length; i++) { + char c = alphabet[random.nextInt(alphabet.length)]; + raw.append(c); + } + String expectedInput = raw.toString().replaceAll("\\s", ""); + byte[] expected; + try { + expected = DataConverter.hexStringToByteArray(expectedInput); + } catch (RuntimeException e) { + expected = null; + } + byte[] actual; + try { + actual = adapter.unmarshal(raw.toString()); + } catch (RuntimeException e) { + actual = null; + } + assertArrayEquals(expected, actual, raw.toString()); + } + } }