[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