| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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.apache.mina.core.buffer; |
| |
| import java.io.UnsupportedEncodingException; |
| |
| /** |
| * Provides utility methods to dump an {@link IoBuffer} into a hex formatted |
| * string. |
| * |
| * @author <a href="http://mina.apache.org">Apache MINA Project</a> |
| */ |
| class IoBufferHexDumper { |
| |
| /** |
| * 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}. |
| */ |
| public static String getHexDumpSlice(final IoBuffer buf, final int offset, final 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(); |
| } |
| |
| /** |
| * Produces a verbose hex dump |
| * |
| * @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) |
| */ |
| public static final String getPrettyHexDumpSlice(final IoBuffer buf, final int offset, final 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(); |
| } |
| |
| /** |
| * 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 |
| */ |
| public static final String toPrettyHexDump(final byte[] data, final int pos, final int len) { |
| if (data == null) { |
| throw new IllegalArgumentException(); |
| } |
| |
| if (len < 0 || pos < 0 || pos + len > data.length) { |
| throw new IndexOutOfBoundsException(); |
| } |
| |
| final StringBuilder b = new StringBuilder(); |
| |
| // Process every byte in the data. |
| |
| for (int i = pos, c = 0, line = 16; i < len; i += line) { |
| b.append(String.format("%06d", Integer.valueOf(c)) + " "); |
| b.append(toPrettyHexDumpLine(data, i, Math.min((pos + len) - i, line), 8, line)); |
| |
| if ((i + line) < len) { |
| b.append("\n"); |
| } |
| |
| c += line; |
| } |
| |
| return b.toString(); |
| |
| } |
| |
| /** |
| * 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 |
| */ |
| private static final String toPrettyHexDumpLine(final byte[] data, final int pos, final int len, final int col, |
| final int line) { |
| if ((line % 2) != 0) { |
| throw new IllegalArgumentException("length must be multiple of 2"); |
| } |
| |
| final StringBuilder b = new StringBuilder(); |
| |
| for (int i = pos, t = Math.min(data.length - pos, len) + pos; i < t;) { |
| for (int x = 0; (x < col) && (i < t); i++, x++) { |
| b.append(toHex(data[i])); |
| b.append(" "); |
| } |
| |
| b.append(" "); |
| } |
| |
| int cl = (line * 3) + (line / col); |
| |
| if (b.length() != cl) // check if we need to pad the output |
| { |
| cl -= b.length(); |
| |
| while (cl > 0) { |
| b.append(" "); |
| cl--; |
| } |
| } |
| |
| try { |
| String p = new String(data, pos, Math.min(data.length - pos, len), "Cp1252").replace("\r\n", "..") |
| .replace("\n", ".").replace("\\", "."); |
| |
| final 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 |
| } |
| } |
| |
| b.append(ch); |
| } catch (final UnsupportedEncodingException e) { |
| e.printStackTrace(); |
| } |
| |
| return b.toString(); |
| } |
| |
| private static final char hexDigit[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', |
| 'F' }; |
| |
| public static final String toHex(final byte b) { |
| // Returns hex String representation of byte |
| |
| final char[] array = { hexDigit[(b >> 4) & 0x0f], hexDigit[b & 0x0f] }; |
| return new String(array); |
| } |
| } |