All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.devzendo.commoncode.string.HexDump Maven / Gradle / Ivy

Go to download

Common utility code (Apache License v2) 2008-2024 Matt Gumbley, DevZendo.org

The newest version!
/*
 * Copyright (C) 2008-2017 Matt Gumbley, DevZendo.org http://devzendo.org
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


package org.devzendo.commoncode.string;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;

/**
 * Hexadecimal routines
 * @author matt
 *
 */
public final class HexDump {
    private HexDump() {
        // not instantiatable
    }

    private static String hexDigits = "0123456789ABCDEF";
    
    /**
     * Convert a byte into its Hex String
     * @param b e.g. 127
     * @return "7F"
     */
    public static String byte2hex(final byte b) {
        final StringBuilder sb = new StringBuilder();
        appendHexByte(sb, b);
        return sb.toString();
    }
    
    /**
     * Convert a number of bytes into their Hex String
     * @param bs e.g. 127, 201
     * @return "7FC9"
     */
    public static String bytes2hex(final byte[] bs) {
        final StringBuilder sb = new StringBuilder();
        for (int i = 0; i < bs.length; i++) {
            appendHexByte(sb, bs[i]);
        }
        return sb.toString();
    }
    
    private static void appendHexByte(final StringBuilder sb, final byte b) {
        sb.append(hexDigits.charAt((b & 0xf0) >> 4));
        sb.append(hexDigits.charAt(b & 0x0f));
    }

    /**
     * Convert a long into its Hex String
     * @param l the long
     * @return a 16 char hex string
     */
    public static String long2hex(final long l) {
        long d = l;
        final char[] buf = new char[16];
        final long mask = 0x0f;
        for (int x = 15; x >= 0; x--) {
            buf[x] = hexDigits.charAt((int) (d & mask));
            d >>>= 4;
        }
        return new String(buf);
    }
    
    /**
     * Convert an int into its hex string
     * @param i the int
     * @return an 8 char hex string
     */
    public static String int2hex(final int i) {
        int d = i;
        final char[] buf = new char[8];
        final long mask = 0x0f;
        for (int x = 7; x >= 0; x--) {
            buf[x] = hexDigits.charAt((int) (d & mask));
            d >>>= 4;
        }
        return new String(buf);
    }
    
    /**
     * Convert a short into its hex string
     * @param s the short
     * @return a 4 char hex string
     */
    public static String short2hex(final short s) {
        short d = s;
        final char[] buf = new char[4];
        final long mask = 0x0f;
        for (int x = 3; x >= 0; x--) {
            buf[x] = hexDigits.charAt((int) (d & mask));
            d >>>= 4;
        }
        return new String(buf);
    }

    /**
     * Dump all of a byte array into a hex/ascii dump
     * @param buffer the byte array
     * @return an array of hex/ascii dump strings
     */
    public static String[] hexDump(final byte[] buffer) {
        if (buffer == null) {
            return new String[0];
        }

        return hexDump(buffer, 0, buffer.length);
    }

    /**
     * Dump some of a byte array into a hex/ascii dump
     * @param buffer the byte array
     * @param startOffset the position in the byte array to start the dump
     * @param dumpLength the number of bytes in the byte array to dump from the startOffset (maximum: the length of buffer)
     * @return an array of hex/ascii dump strings
     */
    public static String[] hexDump(final byte[] buffer, final int startOffset, final int dumpLength) {
        if (buffer == null) {
            return new String[0];
        }

        int offset = startOffset;
        final ArrayList  lines = new ArrayList<>();
        final StringBuilder line = new StringBuilder(80);

        for (int i = 0; i < 78; i++) {
            line.append(' ');
        }

        int left = Math.min(dumpLength, buffer.length - startOffset);
        int upto16;
        byte b;

        while (left > 0) {
            for (int i = 0; i < 78; i++) {
                line.setCharAt(i, ' ');
            }

            line.setCharAt(9, '|');
            line.setCharAt(59, '|');
            line.replace(0, 8, int2hex(offset));
            upto16 = (left > 16) ? 16 : left;

            for (int x = 0; x < upto16; x++) {
                b = buffer[offset + x];
                line.setCharAt(11 + (3 * x), hexDigits.charAt((b & 0xf0) >> 4));
                line.setCharAt(12 + (3 * x), hexDigits.charAt(b & 0x0f));
                line.setCharAt(61 + x, (b >= 32 && b <= 126) ? (char) b : '.');
            }

            lines.add(line.toString());
            offset += 16;
            left -= 16;
        }

        return lines.toArray(new String[0]);
    }

    /**
     * Dump an entire ByteBuffer without affecting the position of the buffer
     * (it gets changed but restored by this routine)
     * @param buffer the buffer
     * @return the lines of hex/ascii dump
     */
    public static String[] hexDump(final ByteBuffer buffer) {
        if (buffer == null) {
            return new String[0];
        }

        final int len = buffer.remaining();
        final byte[] buf = new byte[len];
        final int startPosition = buffer.position();
        buffer.get(buf);
        final String[] ret = hexDump(buf, 0, len);
        buffer.position(startPosition);
        return ret;
    }
    
    /**
     * Convert the first two characters of a hex dump into a byte
     * @param h a string starting with 2 hex characters
     * @return the byte
     */
    public static byte hex2byte(final String h) {
        if (h == null || h.length() < 2) {
            throw new IllegalArgumentException("Cannot decode '" + h + "' as a hex byte");
        }
        return (byte) ((nibble2decimal(h.charAt(0)) << 4) | (nibble2decimal(h.charAt(1))));
    }
    
    /**
     * Convert two hex characters into a byte
     * @param h the most significant nibble
     * @param l the least significant nibble
     * @return the byte
     */
    public static byte hex2byte(final char h, final char l) {
        return (byte) ((nibble2decimal(h) << 4) | (nibble2decimal(l)));
    }

    /**
     * Convert a char in the range [0-9a-fA-F] to its decimal base 10 representation
     * @param nibchar a nibble character
     * @return 0-15.
     */
    public static byte nibble2decimal(final char nibchar) {
        final char n = Character.toUpperCase(nibchar);
        if ((n >= '0' && n <= '9') || (n >= 'A' && n <= 'F') ) {
            return (byte) (Character.isDigit(n) ? n - 0x30 : n - 'A' + 10);
        } else {
            throw new IllegalArgumentException("Cannot decode '" + n + "' as a hex nibble");
        }
    }
    
    /**
     * Convert a hex dump string into the bytes it represents
     * @param hexdump a hexdump, as generated by bytes2hex, e.g. "4142"
     * @return its raw data e.g. the bytes 0x41, 0x42
     */
    public static byte[] hex2bytes(final String hexdump) {
        final int hexdumpLength = hexdump.length();
        if ((hexdumpLength & 0x01) == 0x01) {
            throw new IllegalArgumentException("Cannot decode an odd length hex dump into bytes");
        }
        final byte[] bytes = new byte[hexdumpLength >> 1];
        int j = 0;
        for (int i = 0; i < hexdumpLength; i += 2) {
            bytes[j++] = hex2byte(hexdump.charAt(i), hexdump.charAt(i + 1));
        }
        return bytes;
    }
    
    /**
     * Create a HEX|ASCII dump of a complete buffer.
     * 
     * @param buffer a buffer of bytes
     * @return a dump of the complete buffer starting at offset 0.
     * 
     */
    public static String[] asciiDump(final byte[] buffer) {
        if (buffer == null) {
            return new String[0];
        }

        return asciiDump(buffer, 0, buffer.length);
    }
    
    /**
     * Create a HEX|ASCII dump of part of a buffer, given a start within it.
     * 
     * @param buffer a buffer of bytes
     * @param startOffset the starting offset within the buffer to start the dump at
     * @return the dump of the buffer starting at the start offset
     */
    public static String[] asciiDump(final byte[] buffer, final int startOffset) {
        if (buffer == null) {
            return new String[0];
        }

        return asciiDump(buffer, startOffset, buffer.length);
    }
    
    /**
     * Create an ASCII dump of part of a buffer, given a start and length.
     * 
     * @param buffer a buffer of bytes
     * @param startOffset the starting offset within the buffer to start the dump at.
     * @param bufferLength the number of bytes to dump 
     * @return an ASCII dump
     */
    public static String[] asciiDump(final byte[] buffer, final int startOffset, 
            final int bufferLength) {
        if (buffer == null) {
            return new String[0];
        }

        int offset = startOffset;
        final List lines = new ArrayList();
        final StringBuffer line = new StringBuffer(80);
        for (int i = 0; i < 75; i++) {
            line.append(' ');
        }
        int left = bufferLength;
        int i, upto64, x;
        byte b;
        while (left > 0) {
            for (i = 0; i < 75; i++) {
                line.setCharAt(i, ' ');
            }
            line.setCharAt(9, '|');
            line.replace(0, 8, int2hex(offset));
            upto64 = (left > 64) ? 64 : left;
            for (x = 0; x < upto64; x++) {
                b = buffer[offset + x];
                line.setCharAt(11 + x, (b >= 32 && b < 127) ? (char) b : '.');
            }
            lines.add(line.toString());
            offset += 64;
            left -= 64;
        }
        return lines.toArray(new String[lines.size()]);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy