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);
+    }
+}