You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by el...@apache.org on 2022/02/08 14:29:37 UTC
[mina] branch 2.0.X updated: Applied the addition of a preety hex dumper for IoBuffer (DIRMINA-1133)
This is an automated email from the ASF dual-hosted git repository.
elecharny pushed a commit to branch 2.0.X
in repository https://gitbox.apache.org/repos/asf/mina.git
The following commit(s) were added to refs/heads/2.0.X by this push:
new 68ae3f5 Applied the addition of a preety hex dumper for IoBuffer (DIRMINA-1133)
68ae3f5 is described below
commit 68ae3f5559ce91bc93d9f87c6365615cc843d058
Author: emmanuel lecharny <el...@apache.org>
AuthorDate: Tue Feb 8 15:29:25 2022 +0100
Applied the addition of a preety hex dumper for IoBuffer (DIRMINA-1133)
---
.../apache/mina/core/buffer/AbstractIoBuffer.java | 16 --
.../java/org/apache/mina/core/buffer/IoBuffer.java | 39 +++-
.../apache/mina/core/buffer/IoBufferHexDumper.java | 225 ++++++++++++++++-----
.../apache/mina/core/buffer/IoBufferWrapper.java | 8 -
.../mina/core/buffer/IoBufferHexDumperTest.java | 47 +++++
5 files changed, 257 insertions(+), 78 deletions(-)
diff --git a/mina-core/src/main/java/org/apache/mina/core/buffer/AbstractIoBuffer.java b/mina-core/src/main/java/org/apache/mina/core/buffer/AbstractIoBuffer.java
index aa46c83..5d97142 100644
--- a/mina-core/src/main/java/org/apache/mina/core/buffer/AbstractIoBuffer.java
+++ b/mina-core/src/main/java/org/apache/mina/core/buffer/AbstractIoBuffer.java
@@ -1577,22 +1577,6 @@ public abstract class AbstractIoBuffer extends IoBuffer {
* {@inheritDoc}
*/
@Override
- public String getHexDump() {
- return this.getHexDump(Integer.MAX_VALUE);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String getHexDump(int lengthLimit) {
- return IoBufferHexDumper.getHexdump(this, lengthLimit);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
public String getString(CharsetDecoder decoder) throws CharacterCodingException {
if (!hasRemaining()) {
return "";
diff --git a/mina-core/src/main/java/org/apache/mina/core/buffer/IoBuffer.java b/mina-core/src/main/java/org/apache/mina/core/buffer/IoBuffer.java
index 882ca9c..27c932f 100644
--- a/mina-core/src/main/java/org/apache/mina/core/buffer/IoBuffer.java
+++ b/mina-core/src/main/java/org/apache/mina/core/buffer/IoBuffer.java
@@ -1511,24 +1511,49 @@ public abstract class IoBuffer implements Comparable<IoBuffer> {
* Returns hexdump of this buffer. The data and pointer are not changed as a
* result of this method call.
*
- * @return hexidecimal representation of this buffer
+ * @return hexadecimal representation of this buffer
*/
- public abstract String getHexDump();
+ public String getHexDump() {
+ return this.getHexDump(remaining(), false);
+ }
+
+ /**
+ * Returns hexdump of this buffer. The data and pointer are not changed as a
+ * result of this method call.
+ *
+ * @param pretty Produces multi-line pretty hex dumps
+ * @return hexadecimal representation of this buffer
+ */
+ public String getHexDump(boolean pretty) {
+ return getHexDump(remaining(), pretty);
+ }
/**
* Return hexdump of this buffer with limited length.
*
- * @param lengthLimit
- * The maximum number of bytes to dump from the current buffer
- * position.
+ * @param length The maximum number of bytes to dump from the current buffer
+ * position.
* @return hexidecimal representation of this buffer
*/
- public abstract String getHexDump(int lengthLimit);
+ public String getHexDump(int length) {
+ return getHexDump(length, false);
+ }
+ /**
+ * Return hexdump of this buffer with limited length.
+ *
+ * @param length The maximum number of bytes to dump from the current buffer
+ * position.
+ * @return hexidecimal representation of this buffer
+ */
+ public String getHexDump(int length, boolean pretty) {
+ return (pretty) ? IoBufferHexDumper.getPrettyHexDumpSlice(this, position(), Math.min(remaining(), length))
+ : IoBufferHexDumper.getHexDumpSlice(this, position(), Math.min(remaining(), length));
+ }
+
// //////////////////////////////
// String getters and putters //
// //////////////////////////////
-
/**
* Reads a <code>NUL</code>-terminated string from this buffer using the
* specified <code>decoder</code> and returns it. This method reads until
diff --git a/mina-core/src/main/java/org/apache/mina/core/buffer/IoBufferHexDumper.java b/mina-core/src/main/java/org/apache/mina/core/buffer/IoBufferHexDumper.java
index 4a96bcd..c9f3763 100644
--- a/mina-core/src/main/java/org/apache/mina/core/buffer/IoBufferHexDumper.java
+++ b/mina-core/src/main/java/org/apache/mina/core/buffer/IoBufferHexDumper.java
@@ -19,6 +19,8 @@
*/
package org.apache.mina.core.buffer;
+import java.io.UnsupportedEncodingException;
+
/**
* Provides utility methods to dump an {@link IoBuffer} into a hex formatted
* string.
@@ -26,77 +28,206 @@ package org.apache.mina.core.buffer;
* @author <a href="http://mina.apache.org">Apache MINA Project</a>
*/
class IoBufferHexDumper {
+ private static final char hexDigit[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E',
+ 'F' };
/**
- * The high digits lookup table.
+ * Dumps an {@link IoBuffer} to a hex formatted string.
+ *
+ * @param buf the buffer to dump
+ * @param offset the starting position to begin reading the hex dump
+ * @param length the number of bytes to dump
+ * @return a hex formatted string representation of the <i>in</i>
+ * {@link IoBuffer}.
*/
- private static final byte[] highDigits;
+ public static String getHexDumpSlice(IoBuffer buf, int offset, int length) {
+ if (buf == null) {
+ throw new IllegalArgumentException();
+ }
+
+ if (length < 0 || offset < 0 || offset + length > buf.limit()) {
+ throw new IndexOutOfBoundsException();
+ }
+
+ int pos = offset;
+ int items = Math.min(offset + length, offset + buf.limit()) - pos;
+
+ if (items <= 0) {
+ return "";
+ }
+
+ int lim = pos + items;
+
+ StringBuilder out = new StringBuilder((items * 3) + 6);
+
+ for (;;) {
+ int byteValue = buf.get(pos++) & 0xFF;
+ out.append((char) hexDigit[(byteValue >> 4) & 0x0F]);
+ out.append((char) hexDigit[byteValue & 0xf]);
+ if (pos < lim) {
+ out.append(' ');
+ } else {
+ break;
+ }
+ }
+
+ return out.toString();
+ }
+
/**
- * The low digits lookup table.
+ * Produces a verbose hex dump
+ *
+ * @param buf The buffer to pretty print
+ * @param offset initial position which to read bytes
+ * @param length number of bytes to display
+ *
+ * @return The formatted String representing the content between (offset) and
+ * (offset+count)
*/
- private static final byte[] lowDigits;
+ public static final String getPrettyHexDumpSlice(IoBuffer buf, int offset, int length) {
+ if (buf == null) {
+ throw new IllegalArgumentException();
+ }
+
+ if (length < 0 || offset < 0 || offset + length > buf.limit()) {
+ throw new IndexOutOfBoundsException();
+ }
+
+ final int len = Math.min(length, buf.limit() - offset);
+ final byte[] bytes = new byte[len];
+
+ int o = offset;
+
+ for (int i = 0; i < len; i++) {
+ bytes[i] = buf.get(o++);
+ }
+
+ final StringBuilder sb = new StringBuilder();
+
+ sb.append("Source ");
+ sb.append(buf);
+ sb.append(" showing index ");
+ sb.append(offset);
+ sb.append(" through ");
+ sb.append((offset + length));
+ sb.append("\n");
+ sb.append(toPrettyHexDump(bytes, 0, bytes.length));
+
+ return sb.toString();
+ }
/**
- * Initialize lookup tables.
+ * Generates a hex dump with line numbers, hex, volumes, and ascii
+ * representation
+ *
+ * @param data source data to read for the hex dump
+ *
+ * @param pos index position to begin reading
+ *
+ * @param len number of bytes to read
+ *
+ * @return string hex dump
*/
- static {
- final byte[] digits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+ public static final String toPrettyHexDump(byte[] data, int pos, int len) {
+ if (data == null) {
+ throw new IllegalArgumentException();
+ }
+
+ if (len < 0 || pos < 0 || pos + len > data.length) {
+ throw new IndexOutOfBoundsException();
+ }
- int i;
- byte[] high = new byte[256];
- byte[] low = new byte[256];
+ StringBuilder buffer = new StringBuilder();
- for (i = 0; i < 256; i++) {
- high[i] = digits[i >>> 4];
- low[i] = digits[i & 0x0F];
+ // Process every byte in the data.
+ for (int i = pos, c = 0, line = 16; i < len; i += line) {
+ buffer.append(String.format("%06d", Integer.valueOf(c)) + " ");
+
+ buffer.append(toPrettyHexDumpLine(data, i, Math.min((pos + len) - i, line), 8, line));
+
+ if ((i + line) < len) {
+ buffer.append("\n");
+ }
+
+ c += line;
}
- highDigits = high;
- lowDigits = low;
+ return buffer.toString();
+
}
/**
- * Dumps an {@link IoBuffer} to a hex formatted string.
- *
- * @param in the buffer to dump
- * @param lengthLimit the limit at which hex dumping will stop
- * @return a hex formatted string representation of the <i>in</i> {@link IoBuffer}.
+ * Generates the hex dump line with hex values, columns, and ascii
+ * representation
+ *
+ * @param data source data to read for the hex dump
+ *
+ * @param pos index position to begin reading
+ *
+ * @param len number of bytes to read; this can be less than the <tt>line</tt>
+ * width
+ *
+ * @param col number of bytes in a column
+ *
+ * @param line line width in bytes which pads the output if <tt>len</tt> is less
+ * than <tt>line</tt>
+ *
+ * @return string hex dump
*/
- public static String getHexdump(IoBuffer in, int length) {
- if (length < 0) {
- throw new IllegalArgumentException("length: " + length + " must be non-negative number");
- }
+ private static final String toPrettyHexDumpLine(byte[] data, int pos, int len, int col, int line) {
+ if ((line % 2) != 0) {
+ throw new IllegalArgumentException("length must be multiple of 2");
+ }
+
+ StringBuilder buffer = new StringBuilder();
- int pos = in.position();
- int rem = in.limit() - pos;
- int items = Math.min(rem, length);
+ for (int i = pos, t = Math.min(data.length - pos, len) + pos; i < t;) {
+ for (int x = 0; (x < col) && (i < t); i++, x++) {
+ buffer.append(toHex(data[i]));
+ buffer.append(" ");
+ }
- if (items == 0) {
- return "";
- }
+ buffer.append(" ");
+ }
+
+ int cl = (line * 3) + (line / col);
- int lim = pos + items;
+ if (buffer.length() != cl) // check if we need to pad the output
+ {
+ cl -= buffer.length();
- StringBuilder out = new StringBuilder((items * 3) + 6);
+ while (cl > 0) {
+ buffer.append(" ");
+ cl--;
+ }
+ }
- /* first sequence to align the spaces */{
- int byteValue = in.get(pos++) & 0xFF;
- out.append((char) highDigits[byteValue]);
- out.append((char) lowDigits[byteValue]);
- }
+ try {
+ String p = new String(data, pos, Math.min(data.length - pos, len), "Cp1252").replace("\r\n", "..")
+ .replace("\n", ".").replace("\\", ".");
- /* loop remainder */for (; pos < lim;) {
- out.append(' ');
- int byteValue = in.get(pos++) & 0xFF;
- out.append((char) highDigits[byteValue]);
- out.append((char) lowDigits[byteValue]);
- }
+ char[] ch = p.toCharArray();
+
+ for (int m = 0; m < ch.length; m++) {
+ if (ch[m] < 32) {
+ ch[m] = (char) 46; // add dots for whitespace chars
+ }
+ }
+
+ buffer.append(ch);
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+
+ return buffer.toString();
+ }
- if (items != rem) {
- out.append("...");
- }
+ public static final String toHex(byte b) {
+ // Returns hex String representation of byte
- return out.toString();
+ char[] array = { hexDigit[(b >> 4) & 0x0f], hexDigit[b & 0x0f] };
+
+ return new String(array);
}
}
\ No newline at end of file
diff --git a/mina-core/src/main/java/org/apache/mina/core/buffer/IoBufferWrapper.java b/mina-core/src/main/java/org/apache/mina/core/buffer/IoBufferWrapper.java
index 7616af1..26f51a0 100644
--- a/mina-core/src/main/java/org/apache/mina/core/buffer/IoBufferWrapper.java
+++ b/mina-core/src/main/java/org/apache/mina/core/buffer/IoBufferWrapper.java
@@ -816,14 +816,6 @@ public class IoBufferWrapper extends IoBuffer {
* {@inheritDoc}
*/
@Override
- public String getHexDump() {
- return buf.getHexDump();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
public String getString(int fieldSize, CharsetDecoder decoder) throws CharacterCodingException {
return buf.getString(fieldSize, decoder);
}
diff --git a/mina-core/src/test/java/org/apache/mina/core/buffer/IoBufferHexDumperTest.java b/mina-core/src/test/java/org/apache/mina/core/buffer/IoBufferHexDumperTest.java
new file mode 100644
index 0000000..560a202
--- /dev/null
+++ b/mina-core/src/test/java/org/apache/mina/core/buffer/IoBufferHexDumperTest.java
@@ -0,0 +1,47 @@
+package org.apache.mina.core.buffer;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+public class IoBufferHexDumperTest {
+
+ @Test
+ public void checkHexDumpLength() {
+ IoBuffer buf = IoBuffer.allocate(5000);
+
+ for (int i = 0; i < 20; i++) {
+ buf.putShort((short) 0xF0A0);
+ }
+
+ buf.flip();
+
+ /* special case */
+ assertEquals(0, buf.getHexDump(0).length());
+
+ /* no truncate needed */
+ assertEquals(buf.limit() * 3 - 1, buf.getHexDump().length());
+ assertEquals((Math.min(300, buf.limit()) * 3) - 1, buf.getHexDump(300).length());
+
+ /* must truncate */
+ assertEquals((7 * 3) - 1, buf.getHexDump(7).length());
+ assertEquals((10 * 3) - 1, buf.getHexDump(10).length());
+ assertEquals((30 * 3) - 1, buf.getHexDump(30).length());
+
+ }
+
+ @Test
+ public void checkPrettyHexDumpLength() {
+ IoBuffer buf = IoBuffer.allocate(5000);
+
+ for (int i = 0; i < 20; i++) {
+ buf.putShort((short) 0xF0A0);
+ }
+
+ buf.flip();
+
+ String[] dump = buf.getHexDump(50, true).split("\\n");
+
+ assertEquals(4, dump.length);
+ }
+}