Version 22 of Dump a file in hex and ASCII

Updated 2002-12-13 00:29:45

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 [L1 ].


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 ;-)