Skip to content

Instantly share code, notes, and snippets.

@takumakei
Created April 8, 2011 08:57
Show Gist options
  • Save takumakei/909519 to your computer and use it in GitHub Desktop.
Save takumakei/909519 to your computer and use it in GitHub Desktop.
yet another HexDump
/* HexDump.java
* Yet another HexDump. It prints bytes in human readable text.
*
* Copyright (C) 2011 TAKUMAKei
*
* 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
*
* 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 com.blogspot.takumakei.gist;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import org.slf4j.Logger;
public class HexDump {
public static void dump(byte[] data) {
dump(data, 0, data.length, System.out);
}
public static void dump(byte[] data, int off, int len) {
dump(data, off, len, System.out);
}
public static void dump(byte[] data, PrintStream stream) {
dump(data, 0, data.length, stream);
}
public static void dump(byte[] data, int off, int len, PrintStream stream) {
stream.append(String.format("HexDump [size=%d]", len)).println();
final AddressPrinter addressPrinter;
if (0xFFFFFF < len) {
addressPrinter = new AddressPrinter8();
} else if (0xFFFF < len) {
addressPrinter = new AddressPrinter6();
} else {
addressPrinter = new AddressPrinter4();
}
final int limit = off + len;
while (off < limit) {
addressPrinter.printAddress(stream, off);
stream.append('|');
dumpLine(data, off, limit, stream);
off += 16;
}
stream.flush();
}
public static void dump(byte[] data, String filename) throws IOException {
dump(data, 0, data.length, new File(filename));
}
public static void dump(byte[] data, int off, int len, String filename) throws IOException {
dump(data, off, len, new File(filename));
}
public static void dump(byte[] data, int off, int len, File file) throws IOException {
final PrintStream stream = new PrintStream(file);
try {
dump(data, off, len, stream);
} finally {
stream.close();
}
}
public static void dump(byte[] data, int off, int len, String filename, String csn) throws IOException {
dump(data, off, len, new File(filename), csn);
}
public static void dump(byte[] data, int off, int len, File file, String csn) throws IOException {
final PrintStream stream = new PrintStream(file, csn);
try {
dump(data, off, len, stream);
} finally {
stream.close();
}
}
public static enum Level {
TRACE,
DEBUG,
INFO,
WARN,
ERROR,
}
public static void dump(byte[] data, Logger logger) {
dump(data, 0, data.length, logger, Level.INFO);
}
public static void dump(byte[] data, Logger logger, Level level) {
dump(data, 0, data.length, logger, level);
}
public static void dump(byte[] data, int off, int len, Logger logger) {
dump(data, off, len, logger, Level.INFO);
}
public static void dump(byte[] data, int off, int len, Logger logger, Level level) {
switch (level) {
case TRACE:
dump(data, off, len, new LoggerTracePrintStream(logger));
return;
case DEBUG:
dump(data, off, len, new LoggerDebugPrintStream(logger));
return;
case INFO:
dump(data, off, len, new LoggerInfoPrintStream(logger));
return;
case WARN:
dump(data, off, len, new LoggerWarnPrintStream(logger));
return;
}
dump(data, off, len, new LoggerErrorPrintStream(logger));
}
protected static final char[] HEXCODES = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
};
protected static final byte ASCII_BEGIN = (byte) ' ';
protected static final byte ASCII_END = (byte) '~';
protected static void dumpLine(byte[] data, int off, int limit, PrintStream stream) {
// dump first 8 bytes
dump8Bytes(data, off, limit, stream);
stream.append(' ');
// dump next 8 bytes
dump8Bytes(data, off + 8, limit, stream);
stream.append(" ");
// dump ascii
final int end = Math.min(off + 16, limit);
for (int i = off; i < end; ++i) {
if (ASCII_BEGIN <= data[i] && data[i] <= ASCII_END) {
stream.append((char) data[i]);
} else {
stream.append('.');
}
}
stream.println();
}
protected static void dump8Bytes(byte[] data, int off, int limit, PrintStream stream) {
final int end = off + 8;
if (limit < end) {
int i = off;
for (; i < limit; ++i) {
dumpByte(data[i], stream);
}
for (; i < end; ++i) {
stream.append(" ");
}
} else {
for (int i = off; i < end; ++i) {
dumpByte(data[i], stream);
}
}
}
protected static void dumpByte(byte code, PrintStream stream) {
stream
.append(' ')
.append(HEXCODES[0xf & (code >> 4)])
.append(HEXCODES[0xf & code]);
}
protected static interface AddressPrinter {
public void printAddress(PrintStream stream, int address);
}
protected static class AddressPrinter4 implements AddressPrinter {
@Override
public void printAddress(PrintStream stream, int address) {
stream
.append(HEXCODES[0xf & (address >> 12)])
.append(HEXCODES[0xf & (address >> 8)])
.append(HEXCODES[0xf & (address >> 4)])
.append(HEXCODES[0xf & address]);
}
}
protected static class AddressPrinter6 implements AddressPrinter {
@Override
public void printAddress(PrintStream stream, int address) {
stream
.append(HEXCODES[0xf & (address >> 20)])
.append(HEXCODES[0xf & (address >> 16)])
.append(HEXCODES[0xf & (address >> 12)])
.append(HEXCODES[0xf & (address >> 8)])
.append(HEXCODES[0xf & (address >> 4)])
.append(HEXCODES[0xf & address]);
}
}
protected static class AddressPrinter8 implements AddressPrinter {
@Override
public void printAddress(PrintStream stream, int address) {
stream
.append(HEXCODES[0xf & (address >> 28)])
.append(HEXCODES[0xf & (address >> 24)])
.append(HEXCODES[0xf & (address >> 20)])
.append(HEXCODES[0xf & (address >> 16)])
.append(HEXCODES[0xf & (address >> 12)])
.append(HEXCODES[0xf & (address >> 8)])
.append(HEXCODES[0xf & (address >> 4)])
.append(HEXCODES[0xf & address]);
}
}
private static class ThrowAssertionErrorOnWrite extends OutputStream {
protected static ThrowAssertionErrorOnWrite singleton;
public static ThrowAssertionErrorOnWrite getInstance() {
if (null == singleton) {
singleton = new ThrowAssertionErrorOnWrite();
}
return singleton;
}
@Override
public void write(int b) throws IOException {
throw new AssertionError();
}
};
private static class LoggerPrintStream extends PrintStream {
protected final StringBuilder buffer = new StringBuilder();
protected final Logger logger;
public LoggerPrintStream(Logger logger) {
super(ThrowAssertionErrorOnWrite.getInstance());
this.logger = logger;
}
@Override
public PrintStream append(char ch) {
buffer.append(ch);
return this;
}
@Override
public PrintStream append(CharSequence cs) {
buffer.append(cs);
return this;
}
}
private static class LoggerTracePrintStream extends LoggerPrintStream {
public LoggerTracePrintStream(Logger logger) {
super(logger);
}
@Override
public void println() {
logger.trace(buffer.toString());
buffer.setLength(0);
}
}
private static class LoggerDebugPrintStream extends LoggerPrintStream {
public LoggerDebugPrintStream(Logger logger) {
super(logger);
}
@Override
public void println() {
logger.debug(buffer.toString());
buffer.setLength(0);
}
}
private static class LoggerInfoPrintStream extends LoggerPrintStream {
public LoggerInfoPrintStream(Logger logger) {
super(logger);
}
@Override
public void println() {
logger.info(buffer.toString());
buffer.setLength(0);
}
}
private static class LoggerWarnPrintStream extends LoggerPrintStream {
public LoggerWarnPrintStream(Logger logger) {
super(logger);
}
@Override
public void println() {
logger.warn(buffer.toString());
buffer.setLength(0);
}
}
private static class LoggerErrorPrintStream extends LoggerPrintStream {
public LoggerErrorPrintStream(Logger logger) {
super(logger);
}
@Override
public void println() {
logger.warn(buffer.toString());
buffer.setLength(0);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment