blob: ef02ed31c3a5117f24e5ceb3077331c852185286 [file] [log] [blame]
/*
* 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);
}
}