'''Purpose: ''' Demonstrate the use of the [[binary]] and [[fconfigure]] commands to process a binary file. [KBK] - The following useful Tcl script produces a hex/ASCII dump of a binary file whose name is specified on the command line. ---- package require Tcl 8.3 #---------------------------------------------------------------------- # # dumpFile -- # # Produce a hex/ASCII dump of a file. # # Parameters: # fileName -- Path name of the file # channel -- (Optional) Channel on which to produce the dump. # Default is stdout. # # Results: # None. # # Side effects: # The file is opened, dumped to the specified channel, and # closed again. # #---------------------------------------------------------------------- proc dumpFile { fileName { channel stdout } } { # Open the file, and set up to process it in binary mode. set f [open $fileName r] fconfigure $f \ -translation binary \ -encoding binary \ -buffering full -buffersize 16384 while { 1 } { # Record the seek address. Read 16 bytes from the file. set addr [tell $f] set s [read $f 16] # Convert the data to hex and to characters. binary scan $s H*@0a* hex ascii # Replace non-printing characters in the data. regsub -all -- {[^[:graph:] ]} $ascii {.} ascii # Split the 16 bytes into two 8-byte chunks set hex1 [string range $hex 0 15] set hex2 [string range $hex 16 31] set ascii1 [string range $ascii 0 7] set ascii2 [string range $ascii 8 16] # Convert the hex to pairs of hex digits regsub -all -- {..} $hex1 {& } hex1 regsub -all -- {..} $hex2 {& } hex2 # Put the hex and Latin-1 data to the channel puts $channel [format {%08x %-24s %-24s %-8s %-8s} \ $addr $hex1 $hex2 $ascii1 $ascii2] # Stop if we've reached end of file if { [string length $s] == 0 } { break } } # When we're done, close the file. close $f return } #---------------------------------------------------------------------- # # Main program # #---------------------------------------------------------------------- if { [info exists argv0] && [string equal $argv0 [info script]] } { foreach file $argv { puts "$file:" dumpFile $file } } ---- A slightly different version, derived from the above (not better, just a tiny bit different): proc hexdump { filename { channel stdout } } { # This is derived from the Tcler's WIKI, page 1599, # original author unknown, possibly Kevin Kenny. if { [ catch { # Open the file, and set up to process it in binary mode. set fid [open $filename r] fconfigure $fid -translation binary -encoding binary while { ! [ eof $fid ] } { # Record the seek address. Read 16 bytes from the file. set addr [ tell $fid ] set s [read $fid 16] # Convert the data to hex and to characters. binary scan $s H*@0a* hex ascii # Replace non-printing characters in the data. regsub -all -- {[^[:graph:] ]} $ascii {.} ascii # Split the 16 bytes into two 8-byte chunks regexp -- {(.{16})(.{0,16})} $hex -> hex1 hex2 # Convert the hex to pairs of hex digits regsub -all -- {..} $hex1 {& } hex1 regsub -all -- {..} $hex2 {& } hex2 # Put the hex and Latin-1 data to the channel puts $channel [ format {%08x %-24s %-24s %-16s} \ $addr $hex1 $hex2 $ascii ] } } err ] } { catch { ::close $fid } return -code error $err } # When we're done, close the file. catch { ::close $fid } return } ---- Hmm. What version of TCL was this written for? I'm currently using 8.0, and it doesn't know anything about "[string] equal", or the "-encoding" option to [fconfigure] (which option [Working with binary data] says is unnecessary, anyway.) Other than that, and the fact that my [regsub] doesn't know anything about [[:graph:]], I like this program... '''-EE''' ---- The above code is written for Tcl 8.3.x . The bug features^Wfixes and added features of the 8.3 series is well worth the upgrade. [glennj]: for 8.0, an equivalent regular expression would be something like: {[^ -~]} But this does not accomodate other locales, only ascii characters. ---- [TclKit] appears to build in a copy of hexdump, as above. ''[JCW] - Not any longer as of May 2002 (I've been simplifying TclKit) ... the code has been moved to CritLib, see [CriTcl] and [http://www.equi4.com/critlib/].'' ---- July 31, 2002: Note that the hexdump proc above doesn't appear to do the same thing as the dumpfile proc earlier. Here is some output using my /etc/motd: dumpfile produces: /etc/motd: 00000000 53 75 6e 20 4d 69 63 72 6f 73 79 73 74 65 6d 73 Sun Micr osystems 00000010 20 49 6e 63 2e 09 53 75 6e 4f 53 20 35 2e 36 09 Inc..Su nOS 5.6. 00000020 47 65 6e 65 72 69 63 09 41 75 67 75 73 74 20 31 Generic. August 1 00000030 39 39 37 0a 997. 00000034 hexdump produces: /etc/motd: 00000000 53 75 6e 20 4d 69 63 72 6f 73 79 73 74 65 6d 73 Sun Microsystems 00000010 20 49 6e 63 2e 09 53 75 6e 4f 53 20 35 2e 36 09 Inc..SunOS 5.6. 00000020 47 65 6e 65 72 69 63 09 41 75 67 75 73 74 20 31 Generic.August 1 00000030 47 6 5 6e 6 5 72 6 9 63 0 9 41 7 5 67 7 5 73 7 4 20 3 1 997. I don't think that last line is what the writer intended. '''October 11 2002''' It was fixed almost immediately, then somebody came and reversed the order of the regsub args '''-all --''' to '''-- -all''' and broke it real good @#$^#Q!! It works fine now. '''-PSE''' ---- See also [hexadecimal conversions] for a tiny string2hex - just wrap a file reader around ;-) ----