Skip to content

Commit cb74796

Browse files
Artem LabazinArtem Labazin
authored andcommitted
Add HexUtil class with HEX helper functions
1 parent 8730ff7 commit cb74796

File tree

4 files changed

+206
-2
lines changed

4 files changed

+206
-2
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.0](https://github.com/appulse-projects/utils-java/releases/tag/1.16.0) - 2019-04-24
16+
17+
### Added
18+
19+
- `HexUtil` class with HEX helper functions.
20+
1521
## [1.15.1](https://github.com/appulse-projects/utils-java/releases/tag/1.15.1) - 2019-04-23
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.15.1</version>
27+
<version>1.16.0</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.15.1</tag>
69+
<tag>1.16.0</tag>
7070
</scm>
7171

7272
<distributionManagement>
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
/*
2+
* Copyright 2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.appulse.utils;
18+
19+
import static java.util.Locale.ENGLISH;
20+
21+
import java.util.Formatter;
22+
import java.util.FormatterClosedException;
23+
import java.util.IllegalFormatException;
24+
25+
import lombok.NonNull;
26+
import lombok.val;
27+
28+
/**
29+
* The set of different HEX helper funtions.
30+
*
31+
* @author Artem Labazin
32+
* @since 1.16.0
33+
*/
34+
public final class HexUtil {
35+
36+
private static final String NEW_LINE;
37+
38+
static {
39+
String newLine;
40+
try (Formatter formatter = new Formatter()) {
41+
newLine = formatter.format("%n").toString();
42+
} catch (IllegalFormatException | FormatterClosedException ex) {
43+
newLine = "\n"; // Whaaaaaat?
44+
}
45+
NEW_LINE = newLine;
46+
}
47+
48+
/**
49+
* Converts an integer value into two-chars string with leading 0.
50+
*
51+
* @param value the value to convert
52+
*
53+
* @return the result string
54+
*/
55+
public static String byteToHex (int value) {
56+
return String.format(ENGLISH, "%02x", value);
57+
}
58+
59+
/**
60+
* Converts an integer value into char.
61+
*
62+
* @param value the value to convert
63+
*
64+
* @return the value's {@code char} representation
65+
*/
66+
public static char byteToChar (int value) {
67+
return value <= 0x1F || value >= 0x7F
68+
? '.'
69+
: (char) value;
70+
}
71+
72+
/**
73+
* Returns a multi-line hexadecimal dump of the specified byte array that is easy to read by humans.
74+
*
75+
* @param bytes the byte array to dump
76+
*
77+
* @return the human-readable multi-line hexadecimal dump
78+
*/
79+
public static String prettyHexDump (@NonNull byte[] bytes) {
80+
val buffer = Bytes.wrap(bytes);
81+
return prettyHexDump(buffer);
82+
}
83+
84+
/**
85+
* Returns a multi-line hexadecimal dump of the specified {@link Bytes} that is easy to read by humans.
86+
*
87+
* @param buffer the byte array buffer to dump
88+
*
89+
* @return the human-readable multi-line hexadecimal dump
90+
*/
91+
public static String prettyHexDump (@NonNull Bytes buffer) {
92+
return prettyHexDump(buffer, buffer.readerIndex(), buffer.readableBytes());
93+
}
94+
95+
/**
96+
* Returns a multi-line hexadecimal dump of the specified {@link Bytes} that is easy to read by humans,
97+
* starting at the given {@code offset} using the given {@code length}.
98+
*
99+
* @param buffer the byte array buffer to dump
100+
*
101+
* @param offset the buffer's offset
102+
*
103+
* @param length the dump's length
104+
*
105+
* @return the human-readable multi-line hexadecimal dump
106+
*/
107+
@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
108+
public static String prettyHexDump (@NonNull Bytes buffer, int offset, int length) {
109+
if (offset < 0 || length < 0 || offset + length > buffer.capacity()) {
110+
val msg = String.format(ENGLISH,
111+
"expected: 0 <= offset(%d) <= offset+length(%d) <= buffer.capacity(%d)",
112+
offset, length, buffer.capacity()
113+
);
114+
throw new IndexOutOfBoundsException(msg);
115+
}
116+
if (length == 0) {
117+
return "";
118+
}
119+
120+
val result = new StringBuilder()
121+
.append(" +-------------------------------------------------+").append(NEW_LINE)
122+
.append(" | 0 1 2 3 4 5 6 7 8 9 a b c d e f |").append(NEW_LINE)
123+
.append("+--------+-------------------------------------------------+----------------+");
124+
125+
val elementsInRow = 16;
126+
val rows = (int) Math.ceil(length / (double) elementsInRow);
127+
for (int row = 0; row < rows; row++) {
128+
val hexDump = new StringBuilder(" ");
129+
val asciiDump = new StringBuilder(" ");
130+
131+
val rowStartIndex = row * elementsInRow + offset;
132+
val limit = Math.min(buffer.capacity() - rowStartIndex, elementsInRow);
133+
for (int index = 0; index < limit; index++) {
134+
val value = buffer.getUnsignedByte(rowStartIndex + index);
135+
136+
val hex = byteToHex(value);
137+
val hexIndex = 1 + 3 * index;
138+
hexDump.setCharAt(hexIndex, hex.charAt(0));
139+
hexDump.setCharAt(hexIndex + 1, hex.charAt(1));
140+
141+
asciiDump.setCharAt(index, byteToChar(value));
142+
}
143+
144+
result.append(NEW_LINE)
145+
.append('|').append(String.format(ENGLISH, "%07x0", row)).append('|').append(hexDump).append('|').append(asciiDump).append('|');
146+
}
147+
148+
return result.append(NEW_LINE)
149+
.append("+--------+-------------------------------------------------+----------------+")
150+
.toString();
151+
}
152+
153+
private HexUtil () {
154+
throw new UnsupportedOperationException();
155+
}
156+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright 2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.appulse.utils;
18+
19+
import io.netty.util.internal.ThreadLocalRandom;
20+
import lombok.val;
21+
import org.junit.jupiter.api.Test;
22+
23+
class HexUtilTests {
24+
25+
@Test
26+
void test1 () {
27+
val bytes = new byte[512];
28+
ThreadLocalRandom.current().nextBytes(bytes);
29+
30+
val prettyPrint = HexUtil.prettyHexDump(bytes);
31+
System.out.println(prettyPrint);
32+
}
33+
34+
@Test
35+
void test2 () {
36+
val bytes = new byte[60];
37+
ThreadLocalRandom.current().nextBytes(bytes);
38+
39+
val prettyPrint = HexUtil.prettyHexDump(bytes);
40+
System.out.println(prettyPrint);
41+
}
42+
}

0 commit comments

Comments
 (0)