Groovy Hex Dump
package com.octodecillion.util | |
import static java.lang.Character.* | |
/** | |
* Simple ASCII hex dump of file. | |
* <p> | |
* Example output:<br> | |
* <pre> | |
* OFFSET 0 1 2 3 4 5 6 7 8 9 a b c d e f | ASCII | |
* 00000000: 4c 69 6e 65 20 6f 6e 65 0d 0a 4c 69 6e 65 20 74 | L i n e o n e . . L i n e t | |
* 00000010: 77 6f 0d 0a 4c 69 6e 65 20 74 68 72 65 65 0d 0a | w o . . L i n e t h r e e . . | |
* 00000020: 21 2f 30 31 32 33 34 0d 0a 35 0d 0a 36 37 38 39 | ! / 0 1 2 3 4 . . 5 . . 6 7 8 9 | |
* 00000030: 41 7a | A z | |
* * </pre> | |
* <p> | |
* How to run on Windows cmd shell: | |
* <pre> | |
* hex-dump>groovy -cp src\\groovy;src\\test\\groovy;src\\test src\\groovy\\com\\octodecillion\\util\\HexDump.groovy src\\test\\resources\\test-data-1.txt | |
* </pre> | |
* | |
* @author josef betancourt | |
* | |
*/ | |
class HexDump { | |
/** */ | |
static main(args) { | |
new HexDump().dump(args[0],{println it}) | |
} | |
/** */ | |
public Object dump(filePath, Closure printer){ | |
def file = new File(filePath) | |
printer printHeader() | |
def (startCounter, counter) = [0,0] | |
def bytes = [] | |
file.eachByte{ | |
bytes << it | |
counter++ | |
if( !(counter % NUM_BIN_COLS)){ | |
printer doLine(bytes,startCounter) | |
bytes = [] | |
startCounter=counter | |
} | |
} | |
printer doLine(bytes, startCounter) | |
} | |
/** */ | |
private doLine(List hex, int counter){ | |
if(hex.size()){ | |
def buf = new StringBuffer() | |
buf.append(printCounter(counter,OFFSET_WIDTH,PAD_CHAR,':')) | |
hex.each{ | |
buf.append(printInCol(it,BYTE_WIDTH,PAD_CHAR,'')) | |
} | |
def unusedCols = NUM_BIN_COLS - hex.size() | |
buf.append(( (unusedCols ? (' ' * unusedCols) : '') + ' ' | |
+ HEX_ASCII_SEP)) | |
hex.each{ | |
buf.append((between(it,31,127) ? toString((char)it) | |
+ ' ' : '. ')) | |
} | |
buf | |
} | |
} | |
/** */ | |
private between(value,low, high){ | |
return value >= low && value <= high | |
// (low..high).contains(value) | |
} | |
/** */ | |
private printHeader() { | |
def buf = new StringBuffer() | |
buf.append("OFFSET".padRight(9)) | |
(0..15).each{ | |
buf.append("${toHex(it).padLeft(3)}") | |
} | |
buf.append("${'| ASCII'.padLeft(9)}") | |
buf | |
} | |
/** */ | |
private printCounter(num, padWidth, padChar, suffix){ | |
return printInCol(num,OFFSET_WIDTH,PAD_CHAR,':') | |
} | |
/** */ | |
private printInCol(num, padWidth, padChar, suffix){ | |
return "${toHex(num).padLeft(padWidth,padChar)}$suffix " | |
} | |
/** */ | |
private String toHex(num){ | |
Integer.toString(num,HEX_BASE) | |
} | |
private Closure printer | |
private static final int NUM_BIN_COLS = 16 | |
private static final int BYTE_WIDTH = 2 | |
private static final int COLUMNS = 15 * COL_SIZE | |
private static final String HEX_ASCII_SEP = '| ' | |
private static final String BLANK_COL = ' ' | |
private static final int HEX_BASE = 16 | |
private static final int OFFSET_WIDTH = 8 | |
private static final int COL_SIZE = 2 | |
private static final String PAD_CHAR = '0' | |
} |
/** | |
* | |
*/ | |
package com.octodecillion.util | |
import groovy.lang.GroovyClassLoader.InnerLoader; | |
import org.codehaus.groovy.reflection.ReflectionUtils | |
import static org.junit.Assert.*; | |
import org.junit.Ignore; | |
import org.junit.Test; | |
/** | |
Run of HexDump. | |
<p> | |
Run as Windows cmd: | |
<pre> | |
hex-dump>groovy -cp src\\groovy;src\\test\\groovy src\\test\\groovy\\com\\octodecillion\\util\\HexDumpTest.groovy | |
</pre> | |
In Eclipse 4.3 must create a run configuration with: | |
<pre> | |
Program arguments: | |
--classpath "${workspace_loc:/hex-dump}\src\groovy;${workspace_loc:/hex-dump}\bin;${workspace_loc:/hex-dump}\src\test" --main groovy.ui.GroovyMain "${resource_loc:/hex-dump/src/test/groovy/com/octodecillion/util//HexDumpTest.groovy}" | |
VM arguments: | |
-Dgroovy.home="${groovy_home}" | |
Working directory: | |
${workspace_loc:/hex-dump} | |
Add JUnit 4 library to classpath. | |
</pre> | |
@author jbetancourt | |
*/ | |
class HexDumpTest { | |
private static final String DATA_FILE_1 = | |
"src/test/resources/test-data-1.txt" | |
@Test | |
void headerIsCorrect(){ | |
def expected = 'OFFSET 0 1 2 3 4 5 6 7 8 9 a b c d e f | ASCII' | |
def actual = new HexDump().printHeader() | |
assert expected == actual.toString() | |
} | |
@Test | |
void dump() { | |
def file = new File(DATA_FILE_1) | |
assert file.exists() | |
def lines = [] | |
new HexDump().dump(file.getPath()){ line -> lines << line} | |
def expected = | |
'00000020: 21 2f 30 31 32 33 34 0d 0a 35 0d 0a 36 37 38 39 | ! / 0 1 2 3 4 . . 5 . . 6 7 8 9 ' | |
def cnt = 0 | |
lines.each{ | |
if(cnt++ == 3){ | |
assert (it.toString() | |
== expected) | |
} | |
println it | |
} | |
} | |
@Test | |
void dump2() { | |
def file = new File(DATA_FILE_1) | |
assert file.exists() | |
def lines = [] | |
new HexDump().dump(file.getPath()){ line -> lines << line} | |
def expected = | |
'00000000: 4c 69 6e 65 20 6f 6e 65 0d 0a 4c 69 6e 65 20 74 | L i n e o n e . . L i n e t ' | |
def cnt = 0 | |
lines.each{ | |
if(cnt++ == 1){ | |
assert (it.toString() | |
== expected) | |
} | |
} | |
} | |
} |
This comment has been minimized.
This comment has been minimized.
Thanx for the code. I add dumpText to dump only parcial string test:
|
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This comment has been minimized.
This is a simple ASCII Hex Dump of a file implemented in Groovy language.
The project is structured as: