New function - :hexDump
Posted: 27 Apr 2011 23:57
A much faster version of HEXDUMP.BAT based on CERTUTIL is available at viewtopic.php?f=3&t=8816
Jeb posted a clever technique for reading binary files as an addendum to the ROT13 encryption thread.
I've expanded the concept into a flexible hexDump routine with a good number of options. I've done some testing, but with all the options I wouldn't be surprised if there are some bugs lurking somewhere. In theory it should be able to handle reading up to 2 gigabytes, but I don't recommend it! As long as the /S option startOffset is in the tens of thousands then performance isn't too bad. But I tried looking at 200 bytes with startOffset=200000 and the wait was painful.
hexDump.bat
Here is output using a few of the options. I dumped the 1st 200 bytes of the hexDump.bat file.
Dave Benham
Jeb posted a clever technique for reading binary files as an addendum to the ROT13 encryption thread.
I've expanded the concept into a flexible hexDump routine with a good number of options. I've done some testing, but with all the options I wouldn't be surprised if there are some bugs lurking somewhere. In theory it should be able to handle reading up to 2 gigabytes, but I don't recommend it! As long as the /S option startOffset is in the tens of thousands then performance isn't too bad. But I tried looking at 200 bytes with startOffset=200000 and the wait was painful.
hexDump.bat
Code: Select all
@echo off
:hexDump [/option]... file -- dump a file in hex format
::
:: Displays the content of a binary file using a pair of hexadecimal digits
:: for each byte. By default the ouput displays 16 bytes per line, with the
:: the bytes (hexadecimal pairs) delimited by a space.
::
:: The format of the dump can be modified by the following case insensitive
:: options:
::
:: /BblockSize The blockSize after the /B specifies the number of bytes
:: to print in each block. Bytes within a block are not
:: delimited. If the blockSize is <= 0 then /C, /A and /O
:: options are ignored and the bytes are output in a
:: continuous stream without any delimiters or linebreaks.
:: The default blockSize is 1.
::
:: /CblockCount The blockCount after the /C specifies the number of blocks
:: to include on each line of output. Blocks are delimited
:: by a space.
:: The default blockCount is 16.
::
:: /SstartOffset The startOffset after the /S specifies the number of bytes
:: to skip before displaying bytes.
:: The default startOffset is 0.
::
:: /Nlengh The length after the /N specifies the total number of
:: bytes to display after the startOffset. The default is to
:: display up until the end of the file.
::
:: /A Append the ASCII representation of the bytes to the end
:: of each line. Non-printable and extended ASCII characters
:: are displayed as periods.
::
:: /O Prefix each line with the starting offset of the line in
:: hexadecimal notation.
::
:: Each option must be entered as a separate argument.
::
setlocal enableDelayedExpansion
set /a blockSize=1, blockCount=16, startOffset=0
set ascii=
set offset=
set len=
set opts=
for %%a in (%*) do (
if not defined opts (
set "arg=%%~a"
if "!arg:~0,1!"=="/" (
shift /1
set "opt=!arg:~1,1!"
if /i "!opt!"=="B" set /a blockSize=!arg:~2!
if /i "!opt!"=="C" set /a blockCount=!arg:~2!
if /i "!opt!"=="S" set /a startOffset=!arg:~2!
if /i "!opt!"=="N" set /a len=!arg:~2!
if /i "!opt!"=="A" set "ascii= "
if /i "!opt!"=="O" set offset=TRUE
) else set opts=TRUE
)
)
if not exist %1 (
echo ERROR: File not found >&2
exit /b 1
)
set fileSize=%~z1
if defined len (
set /a "endOffset = startOffset + len"
if !endOffset! gtr %fileSise% set endOffset=%fileSize%
) else set endOffset=%fileSize%
if defined offset set offset=%startOffset%
set "blockDelim= "
if %blockSize% lss 1 (
set /a "blockSize=0, blockCount=2000"
set "ascii="
set "offset="
set "blockDelim="
)
set dummy="!temp!\hexDumpDummy%random%.txt"
<nul >%dummy% set /p ".=A"
set dummySize=1
for /l %%n in (1,1,32) do (if !dummySize! lss %endOffset% set /a "dummySize*=2" & type !dummy! >>!dummy!)
set /a "pos=0, cnt=0, skipStart=startOffset+1, lnBytes=blockSize*blockCount"
set "off="
set "hex="
set "txt=%ascii%"
set map= ^^^!^"#$%%^&'^(^)*+,-./0123456789:;^<=^>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^^^^_`abcdefghijklmnopqrstuvwxyz{^|}~
set hexMap=0123456789ABCDEF
for /f "eol=F usebackq tokens=1,2 skip=1 delims=:[] " %%A in (`fc /b "%~dpf1" %dummy%`) do (
set /a skipEnd=0x%%A && (
if !skipEnd! geq %startOffset% if !skipStart! leq %endOffset% (
for /l %%n in (!skipStart!,1,!skipEnd!) do call :hexDump.addChar 41
call :hexDump.addChar %%B
set /a skipStart=skipEnd+2
)
)
)
for /l %%n in (%skipStart%,1,%endOffset%) do call :hexDump.addChar 41
if %blockSize%==0 if defined hex call :hexDump.writeLn
for /l %%n in (1,1,%lnBytes%) do if defined hex call :hexDump.addChar " "
del %dummy%
exit /b
:hexDump.addChar hexPair
set "hex=!hex!%~1"
if defined ascii (
2>nul set /a "d=0x%1-32" && (
if !d! lss 0 set d=14
if !d! gtr 94 set d=14
for %%d in (!d!) do set txt=!txt!!map:~%%d,1!
)
)
if %blockSize% gtr 0 set /a pos+=1
if !pos!==%blockSize% set /a "pos=0, cnt+=1"
if not !cnt!==!blockCount! (
if !pos!==0 set "hex=!hex!%blockDelim%"
exit /b
)
set cnt=0
:hexDump.writeLn
if defined offset (
set off=
set dec=!offset!
for /l %%n in (1,1,8) do (
set /a "d=dec&15,dec>>=4"
for %%d in (!d!) do set "off=!hexMap:~%%d,1!!off!"
)
set "off=!off!: "
set /a offset+=lnBytes
)
set "ln=!off!!hex!!txt!"
if %blockSize%==0 (<nul set /p ".=!ln!") else echo !ln!
set hex=
set "txt=%ascii%"
exit /b
Code: Select all
>hexdump /a /o /n200 hexdump.bat
00000000: 40 65 63 68 6F 20 6F 66 66 0D 0A 3A 68 65 78 44 @echo off..:hexD
00000010: 75 6D 70 20 5B 2F 6F 70 74 69 6F 6E 5D 2E 2E 2E ump [/option]...
00000020: 20 66 69 6C 65 20 20 2D 2D 20 64 75 6D 70 20 61 file -- dump a
00000030: 20 66 69 6C 65 20 69 6E 20 68 65 78 20 66 6F 72 file in hex for
00000040: 6D 61 74 0D 0A 3A 3A 0D 0A 3A 3A 20 20 44 69 73 mat..::..:: Dis
00000050: 70 6C 61 79 73 20 74 68 65 20 63 6F 6E 74 65 6E plays the conten
00000060: 74 20 6F 66 20 61 20 62 69 6E 61 72 79 20 66 69 t of a binary fi
00000070: 6C 65 20 75 73 69 6E 67 20 61 20 70 61 69 72 20 le using a pair
00000080: 6F 66 20 68 65 78 61 64 65 63 69 6D 61 6C 20 64 of hexadecimal d
00000090: 69 67 69 74 73 0D 0A 3A 3A 20 20 66 6F 72 20 65 igits..:: for e
000000A0: 61 63 68 20 62 79 74 65 2E 20 42 79 20 64 65 66 ach byte. By def
000000B0: 61 75 6C 74 20 74 68 65 20 6F 75 70 75 74 20 64 ault the ouput d
000000C0: 69 73 70 6C 61 79 73 20 isplays