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

com.fluxtion.agrona.PrintBufferUtil Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2014-2024 Real Logic Limited.
 * Copyright 2012 The Netty Project
 *
 * 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
 *
 * https://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 com.fluxtion.agrona;

/**
 * Useful utils to hex dump the Agrona's buffers.
 * 

* This is code adapted from the Netty project adopted to support {@link DirectBuffer}. */ public final class PrintBufferUtil { private static final String NEWLINE = System.lineSeparator(); private static final String EMPTY_STRING = ""; private static final String[] BYTE2HEX_PAD = new String[256]; static { int i; for (i = 0; i < 10; i++) { BYTE2HEX_PAD[i] = "0" + i; } for (; i < 16; i++) { final char c = (char)('a' + i - 10); BYTE2HEX_PAD[i] = "0" + c; } for (; i < BYTE2HEX_PAD.length; i++) { BYTE2HEX_PAD[i] = Integer.toHexString(i); } } private PrintBufferUtil() { } /** * Returns a hex dump * of the specified buffer's readable bytes. * * @param buffer dumped buffer. * @return hex dump in a string representation. */ public static String hexDump(final DirectBuffer buffer) { return hexDump(buffer, 0, buffer.capacity()); } /** * Returns a hex dump * of the specified buffer's subregion. * * @param buffer dumped buffer. * @param fromIndex where should we start to print. * @param length how much should we print. * @return hex dump in a string representation. */ public static String hexDump(final DirectBuffer buffer, final int fromIndex, final int length) { return HexUtil.hexDump(buffer, fromIndex, length); } /** * Returns a hex dump * of the specified byte array. * * @param array dumped array. * @return hex dump in a string representation. */ public static String hexDump(final byte[] array) { return hexDump(array, 0, array.length); } /** * Returns a hex dump * of the specified byte array's subregion. * * @param array dumped array. * @param fromIndex where should we start to print. * @param length how much should we print. * @return hex dump in a string representation. */ public static String hexDump(final byte[] array, final int fromIndex, final int length) { return HexUtil.hexDump(array, fromIndex, length); } /** * Returns a hexadecimal dump of the specified {@link DirectBuffer} that is easy to read by humans. * * @param buffer dumped buffer. * @return pretty hex dump in a string representation. */ public static String prettyHexDump(final DirectBuffer buffer) { return prettyHexDump(buffer, 0, buffer.capacity()); } /** * Returns a hexadecimal dump of the specified {@link DirectBuffer} that is easy to read by humans, * starting at the given {@code offset} using the given {@code length}. * * @param buffer dumped buffer. * @param offset where should we start to print. * @param length how much should we print. * @return pretty hex dump in a string representation. */ public static String prettyHexDump(final DirectBuffer buffer, final int offset, final int length) { return HexUtil.prettyHexDump(buffer, offset, length); } /** * Appends the prettified multi-line hexadecimal dump of the specified {@link DirectBuffer} to the specified * {@link StringBuilder} that is easy to read by humans. * * @param dump where should we append string representation of the buffer. * @param buffer dumped buffer. */ public static void appendPrettyHexDump(final StringBuilder dump, final DirectBuffer buffer) { appendPrettyHexDump(dump, buffer, 0, buffer.capacity()); } /** * Appends the prettified multi-line hexadecimal dump of the specified {@link DirectBuffer} to the specified * {@link StringBuilder} that is easy to read by humans, starting at the given {@code offset} using * the given {@code length}. * * @param dump where should we append string representation of the buffer. * @param buffer dumped buffer. * @param offset where should we start to print. * @param length how much should we print. */ public static void appendPrettyHexDump( final StringBuilder dump, final DirectBuffer buffer, final int offset, final int length) { HexUtil.appendPrettyHexDump(dump, buffer, offset, length); } /** * Converts the specified byte value into a 2-digit hexadecimal integer. * * @param value converted value. * @return hex representation of the value. */ public static String byteToHexStringPadded(final int value) { return BYTE2HEX_PAD[value & 0xff]; } static final class HexUtil { private static final char[] BYTE2CHAR = new char[256]; private static final char[] HEXDUMP_TABLE = new char[256 * 4]; private static final String[] HEX_PADDING = new String[16]; private static final String[] HEXDUMP_ROW_PREFIXES = new String[65536 >>> 4]; private static final String[] BYTE2HEX = new String[256]; private static final String[] BYTE_PADDING = new String[16]; static { final char[] digits = "0123456789abcdef".toCharArray(); for (int i = 0; i < 256; i++) { HEXDUMP_TABLE[i << 1] = digits[i >>> 4 & 0x0F]; HEXDUMP_TABLE[(i << 1) + 1] = digits[i & 0x0F]; } int i; // Generate the lookup table for hex dump padding for (i = 0; i < HEX_PADDING.length; i++) { final int padding = HEX_PADDING.length - i; final StringBuilder buf = new StringBuilder(padding * 3); for (int j = 0; j < padding; j++) { buf.append(" "); } HEX_PADDING[i] = buf.toString(); } // Generate the lookup table for the start-offset header in each row (up to 64 KiB). for (i = 0; i < HEXDUMP_ROW_PREFIXES.length; i++) { final StringBuilder buf = new StringBuilder(12); buf.append(NEWLINE); buf.append(Long.toHexString((long)i << 4 & 0xFFFFFFFFL | 0x100000000L)); buf.setCharAt(buf.length() - 9, '|'); buf.append('|'); HEXDUMP_ROW_PREFIXES[i] = buf.toString(); } // Generate the lookup table for byte-to-hex-dump conversion for (i = 0; i < BYTE2HEX.length; i++) { BYTE2HEX[i] = ' ' + byteToHexStringPadded(i); } // Generate the lookup table for byte dump paddings for (i = 0; i < BYTE_PADDING.length; i++) { final int padding = BYTE_PADDING.length - i; final StringBuilder buf = new StringBuilder(padding); for (int j = 0; j < padding; j++) { buf.append(' '); } BYTE_PADDING[i] = buf.toString(); } // Generate the lookup table for byte-to-char conversion for (i = 0; i < BYTE2CHAR.length; i++) { BYTE2CHAR[i] = (i <= 0x1f || i >= 0x7f) ? '.' : (char)i; } } /** * Gets an unsigned byte at the specified absolute {@code index} in a buffer. * * @param buffer the source of value. * @param index the absolute {@code index} in the buffer. * @return unsigned byte value. */ static short getUnsignedByte(final DirectBuffer buffer, final int index) { return (short)(buffer.getByte(index) & 0xFF); } static String hexDump(final DirectBuffer buffer, final int fromIndex, final int length) { if (length < 0) { throw new IllegalArgumentException("length: " + length); } if (length == 0) { return ""; } final int endIndex = fromIndex + length; final char[] buf = new char[length << 1]; for (int dstIdx = 0, srcIdx = fromIndex; srcIdx < endIndex; srcIdx++, dstIdx += 2) { System.arraycopy( HEXDUMP_TABLE, getUnsignedByte(buffer, srcIdx) << 1, buf, dstIdx, 2); } return new String(buf); } static String hexDump(final byte[] array, final int fromIndex, final int length) { if (length < 0) { throw new IllegalArgumentException("length < 0: " + length); } if (length == 0) { return ""; } final int endIndex = fromIndex + length; final char[] buf = new char[length << 1]; for (int dstIdx = 0, srcIdx = fromIndex; srcIdx < endIndex; srcIdx++, dstIdx += 2) { System.arraycopy( HEXDUMP_TABLE, (array[srcIdx] & 0xFF) << 1, buf, dstIdx, 2); } return new String(buf); } static String prettyHexDump(final DirectBuffer buffer, final int offset, final int length) { if (length == 0) { return EMPTY_STRING; } else { final int rows = length / 16 + (length % 15 == 0 ? 0 : 1) + 4; final StringBuilder stringBuilder = new StringBuilder(rows * 80); appendPrettyHexDump(stringBuilder, buffer, offset, length); return stringBuilder.toString(); } } /** * Determine if the requested {@code index} and {@code length} will fit within {@code capacity}. * * @param index The starting index. * @param length The length which will be utilized (starting from {@code index}). * @param capacity The capacity that {@code index + length} is allowed to be within. * @return {@code true} if the requested {@code index} and {@code length} will fit within {@code capacity}. * {@code false} if this would result in an index out of bounds exception. */ static boolean isOutOfBounds(final int index, final int length, final int capacity) { return (index | length | (index + length) | (capacity - (index + length))) < 0; } static void appendPrettyHexDump( final StringBuilder dump, final DirectBuffer buffer, final int offset, final int length) { if (isOutOfBounds(offset, length, buffer.capacity())) { throw new IndexOutOfBoundsException( "expected: " + "0 <= offset(" + offset + ") <= offset + length(" + length + ") <= " + "buffer.capacity(" + buffer.capacity() + ')'); } if (length == 0) { return; } dump.append(" +-------------------------------------------------+") .append(NEWLINE) .append(" | 0 1 2 3 4 5 6 7 8 9 a b c d e f |") .append(NEWLINE) .append("+--------+-------------------------------------------------+----------------+"); final int fullRows = length >>> 4; final int remainder = length & 0xF; // Dump the rows which have 16 bytes. for (int row = 0; row < fullRows; row++) { final int rowStartIndex = (row << 4) + offset; appendHexDumpRowPrefix(dump, row, rowStartIndex); final int rowEndIndex = rowStartIndex + 16; for (int j = rowStartIndex; j < rowEndIndex; j++) { dump.append(BYTE2HEX[getUnsignedByte(buffer, j)]); } dump.append(" |"); for (int j = rowStartIndex; j < rowEndIndex; j++) { dump.append(BYTE2CHAR[getUnsignedByte(buffer, j)]); } dump.append('|'); } // Dump the last row which has less than 16 bytes. if (remainder != 0) { final int rowStartIndex = (fullRows << 4) + offset; appendHexDumpRowPrefix(dump, fullRows, rowStartIndex); final int rowEndIndex = rowStartIndex + remainder; for (int j = rowStartIndex; j < rowEndIndex; j++) { dump.append(BYTE2HEX[getUnsignedByte(buffer, j)]); } dump.append(HEX_PADDING[remainder]); dump.append(" |"); for (int j = rowStartIndex; j < rowEndIndex; j++) { dump.append(BYTE2CHAR[getUnsignedByte(buffer, j)]); } dump.append(BYTE_PADDING[remainder]); dump.append('|'); } dump.append(NEWLINE) .append("+--------+-------------------------------------------------+----------------+"); } static void appendHexDumpRowPrefix(final StringBuilder dump, final int row, final int rowStartIndex) { if (row < HEXDUMP_ROW_PREFIXES.length) { dump.append(HEXDUMP_ROW_PREFIXES[row]); } else { dump.append(NEWLINE); dump.append(Long.toHexString(rowStartIndex & 0xFFFFFFFFL | 0x100000000L)); dump.setCharAt(dump.length() - 9, '|'); dump.append('|'); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy