Skip to content

Commit 609d4ad

Browse files
Artem LabazinArtem Labazin
authored andcommitted
Add HEX string convertion
1 parent cb74796 commit 609d4ad

File tree

4 files changed

+95
-5
lines changed

4 files changed

+95
-5
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
1212
- Add more tests.
1313
- Add `JavaDoc`.
1414

15+
## [1.16.1](https://github.com/appulse-projects/utils-java/releases/tag/1.16.1) - 2019-04-26
16+
17+
### Added
18+
19+
- `HexUtil` to/from HEX string and byte array converter methods.
20+
1521
## [1.16.0](https://github.com/appulse-projects/utils-java/releases/tag/1.16.0) - 2019-04-24
1622

1723
### Added

pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ limitations under the License.
2424

2525
<groupId>io.appulse</groupId>
2626
<artifactId>utils-java</artifactId>
27-
<version>1.16.0</version>
27+
<version>1.16.1</version>
2828
<packaging>jar</packaging>
2929

3030
<properties>
@@ -66,7 +66,7 @@ limitations under the License.
6666
<url>https://github.com/appulse-projects/utils-java</url>
6767
<connection>scm:git:https://github.com/appulse-projects/utils-java.git</connection>
6868
<developerConnection>scm:git:https://github.com/appulse-projects/utils-java.git</developerConnection>
69-
<tag>1.16.0</tag>
69+
<tag>1.16.1</tag>
7070
</scm>
7171

7272
<distributionManagement>

src/main/java/io/appulse/utils/HexUtil.java

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,62 @@ public final class HexUtil {
4545
NEW_LINE = newLine;
4646
}
4747

48+
private static final char[] HEX_CODES = "0123456789ABCDEF".toCharArray();
49+
50+
/**
51+
* Converts an array of bytes into a string.
52+
*
53+
* @param bytes an array of bytes
54+
*
55+
* @return a string containing a lexical representation of HEX binary
56+
*
57+
* @throws NullpointerException if {@code bytes} is null.
58+
*
59+
* @since 1.16.1
60+
*/
61+
public static String toHexString (@NonNull byte[] bytes) {
62+
val result = new StringBuilder(bytes.length * 2);
63+
for (val value : bytes) {
64+
result.append(HEX_CODES[(value >> 4) & 0xF]);
65+
result.append(HEX_CODES[value & 0xF]);
66+
}
67+
return result.toString();
68+
}
69+
70+
/**
71+
* Converts the string argument into an array of bytes.
72+
*
73+
* @param string a string containing lexical representation of HEX binary.
74+
*
75+
* @return an array of bytes represented by the string argument.
76+
*
77+
* @throws NullpointerException if {@code string} is null.
78+
*
79+
* @throws IllegalArgumentException if string parameter does not conform to lexical
80+
* value space defined for HEX binary.
81+
*
82+
* @since 1.16.1
83+
*/
84+
public static byte[] toByteArray (@NonNull String string) {
85+
val length = string.length();
86+
if (length % 2 != 0) {
87+
val msg = String.format(ENGLISH, "hexBinary needs to be even-length: %s", string);
88+
throw new IllegalArgumentException(msg);
89+
}
90+
91+
val result = new byte[length / 2];
92+
for (int index = 0; index < length; index += 2) {
93+
int hight = hexToBin(string.charAt(index));
94+
int low = hexToBin(string.charAt(index + 1));
95+
if (hight == -1 || low == -1) {
96+
val msg = String.format(ENGLISH, "contains illegal character for hexBinary: %s", string);
97+
throw new IllegalArgumentException(msg);
98+
}
99+
result[index / 2] = (byte) (hight * 16 + low);
100+
}
101+
return result;
102+
}
103+
48104
/**
49105
* Converts an integer value into two-chars string with leading 0.
50106
*
@@ -133,10 +189,9 @@ public static String prettyHexDump (@NonNull Bytes buffer, int offset, int lengt
133189
for (int index = 0; index < limit; index++) {
134190
val value = buffer.getUnsignedByte(rowStartIndex + index);
135191

136-
val hex = byteToHex(value);
137192
val hexIndex = 1 + 3 * index;
138-
hexDump.setCharAt(hexIndex, hex.charAt(0));
139-
hexDump.setCharAt(hexIndex + 1, hex.charAt(1));
193+
hexDump.setCharAt(hexIndex, HEX_CODES[(value >> 4) & 0xF]);
194+
hexDump.setCharAt(hexIndex + 1, HEX_CODES[value & 0xF]);
140195

141196
asciiDump.setCharAt(index, byteToChar(value));
142197
}
@@ -150,6 +205,17 @@ public static String prettyHexDump (@NonNull Bytes buffer, int offset, int lengt
150205
.toString();
151206
}
152207

208+
private static int hexToBin (char character) {
209+
if (Character.isDigit(character)) {
210+
return character - '0';
211+
}
212+
213+
val letter = Character.toUpperCase(character);
214+
return 'A' <= letter && letter <= 'F'
215+
? letter - 'A' + 10
216+
: -1;
217+
}
218+
153219
private HexUtil () {
154220
throw new UnsupportedOperationException();
155221
}

src/test/java/io/appulse/utils/HexUtilTests.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package io.appulse.utils;
1818

19+
import static org.assertj.core.api.Assertions.assertThat;
20+
1921
import io.netty.util.internal.ThreadLocalRandom;
2022
import lombok.val;
2123
import org.junit.jupiter.api.Test;
@@ -39,4 +41,20 @@ void test2 () {
3941
val prettyPrint = HexUtil.prettyHexDump(bytes);
4042
System.out.println(prettyPrint);
4143
}
44+
45+
@Test
46+
void toHexToByteArray () {
47+
val bytes = new byte[] {
48+
(byte) 0xDB, (byte) 0x68, (byte) 0xFE, (byte) 0x74, (byte) 0x59,
49+
(byte) 0x7A, (byte) 0x9A, (byte) 0xC1, (byte) 0xCF, (byte) 0x27,
50+
(byte) 0xCE, (byte) 0x65, (byte) 0x64, (byte) 0x08, (byte) 0xC8
51+
};
52+
53+
val string = HexUtil.toHexString(bytes);
54+
assertThat(string)
55+
.isEqualTo("DB68FE74597A9AC1CF27CE656408C8");
56+
57+
assertThat(HexUtil.toByteArray(string))
58+
.isEqualTo(bytes);
59+
}
4260
}

0 commit comments

Comments
 (0)