[9] RFR 8170769: Provide a simple hexdump facility for binary data
Paul Sandoz
paul.sandoz at oracle.com
Thu Dec 8 20:08:08 UTC 2016
Hi,
It may take a few iterations to get the API settled.
There are other byte sources we may want to consider such as InputStream and ByteBuffer.
Comments below.
Paul.
> On 7 Dec 2016, at 08:32, Vincent Ryan <vincent.x.ryan at oracle.com> wrote:
>
> A hexdump facility has been available for many, many years via an unsupported class: sun.misc.HexDumpEncoder.
> Although that class was always unsupported, it was still accessible. That accessibility changes with Jigsaw so I’m proposing
> a very simple replacement in a new and supported class: java.util.HexDump.
>
> Thanks.
>
> Bug: https://bugs.openjdk.java.net/browse/JDK-8170769
> Webrev: http://cr.openjdk.java.net/~vinnie/8170769/webrev.00/
>
55 if (bytes == null) {
56 throw new NullPointerException();
57 }
Objects.requireNonNull
78 * @throws IllegalArgumentException if {@code hexString} has an odd number
79 * of digits
80 * @throws NullPointerException if {@code hexString} is {@code null}
81 */
82 public static byte[] fromHexString(String hexString) {
This should accept a CharSequence, plus also have bounded range equivalent.
Also throws IAE if the hexString contains non-convertible characters.
106 /**
107 * Generates a stream of hexadecimal strings, in 16-byte chunks,
108 * from the contents of a binary buffer.
109 *
110 * @param bytes a binary buffer
111 * @return a stream of hexadecimal strings
112 * @throws NullPointerException if {@code bytes} is {@code null}
113 */
114 public static Stream<String> dumpToStream(byte[] bytes) {
115 if (bytes == null) {
116 throw new NullPointerException();
117 }
118 return StreamSupport.stream(
119 Spliterators.spliteratorUnknownSize(
120 new HexDumpIterator(bytes),
121 Spliterator.ORDERED | Spliterator.NONNULL),
122 false);
123 }
I suspect there is no need for a HexDumpIterator and you can do:
return IntStream.range(0, roundUp(bytes.length, 16)).mapToObject(…);
and in the map function take care of the trailing bytes based on the byte[] length. That’s potentially simple enough there might be no need for a stream method. Where it gets more complicated is if the source is of unknown size such as InputStream, where the stream returning method probably has more value.
Ideally what we want to return is Stream<[Long, String]>, then it’s really easy for others for format, but alas the current form would be ugly and inefficient. So i suspect the dump method has some legs but it’s real value may be for a fully streaming solution.
140 public static String dump(byte[] bytes) {
141 if (bytes == null) {
142 throw new NullPointerException();
143 }
144
145 int[] count = { -16 };
146 return dumpToStream(bytes).collect(Collector.of(
147 StringBuilder::new,
148 (stringBuilder, hexString) ->
149 stringBuilder
150 .append(String.format("%08x %s%n",
151 (count[0] += CHUNK_LENGTH),
152 explode(hexString))),
153 StringBuilder::append,
154 StringBuilder::toString));
155 }
The encoding of the count and exploding could also append directly into the main string builder, reducing memory churn.
And i think you can also start from IntStream.range(0, roundUp(bytes.length, 16)) avoiding the count state.
192 if (b < ' ' || b > '~') {
193 sb.append(".”);
Use ‘.’
194 } else {
195 sb.append(new String(new byte[]{ b }));
Cast the byte to a char instead.
196 }
More information about the core-libs-dev
mailing list